Solidity基础语法 #

一、注释 #

1.1 单行注释 #

使用//进行单行注释:

solidity
// 这是一个单行注释
uint256 public count; // 变量声明后的注释

1.2 多行注释 #

使用/* */进行多行注释:

solidity
/*
 * 这是一个多行注释
 * 可以跨越多行
 * 用于详细说明
 */
contract MyContract {
    /* 
       合约逻辑
       在这里实现
    */
}

1.3 文档注释(NatSpec) #

Solidity支持Ethereum Natural Language Specification(NatSpec)格式的文档注释:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title 简单存储合约
 * @author 开发者名称
 * @notice 这是一个用于演示的合约
 * @dev 详细开发说明
 */
contract SimpleStorage {
    uint256 private _count;

    /**
     * @notice 设置计数值
     * @param newCount 新的计数值
     * @dev 只有owner可以调用此函数
     */
    function setCount(uint256 newCount) public {
        _count = newCount;
    }

    /**
     * @notice 获取当前计数值
     * @return 当前存储的计数值
     */
    function getCount() public view returns (uint256) {
        return _count;
    }
}

1.4 NatSpec标签 #

标签 说明 使用场景
@title 合约标题 描述合约用途
@author 作者信息 标注开发者
@notice 用户说明 面向终端用户
@dev 开发说明 面向开发者
@param 参数说明 函数参数
@return 返回值说明 函数返回值
@inheritdoc 继承文档 从父合约继承文档
@custom 自定义标签 扩展用途

二、标识符 #

2.1 命名规则 #

标识符用于命名合约、函数、变量等,必须遵循以下规则:

规则 说明 示例
字符组成 字母、数字、下划线 myVar, _count, value1
首字符 字母或下划线 name, _private
大小写敏感 Namename不同 区分对待
不能是关键字 避免保留字 不能用contract作变量名

2.2 合法标识符 #

solidity
// 合法的标识符
contract MyContract {}
function myFunction() {}
uint256 my_variable;
uint256 _privateVar;
uint256 count1;

2.3 非法标识符 #

solidity
// 非法的标识符
// uint256 1count;        // 不能以数字开头
// uint256 my-var;        // 不能包含连字符
// uint256 contract;      // 不能使用关键字
// uint256 my variable;   // 不能包含空格

三、关键字 #

3.1 保留关键字 #

Solidity保留关键字不能用作标识符:

solidity
// 这些是关键字,不能用作变量名
// abstract, after, alias, apply, auto, byte, case, catch, constant
// contract, constructor, continue, contract, days, else, emit, enum
// ether, event, external, fallback, false, finney, for, function
// gwei, hours, if, immutable, import, indexed, interface, internal
// is, let, mapping, match, memory, minutes, modifier, new, override
// payable, pragma, private, public, pure, receive, return, returns
// revert, seconds, storage, struct, suicode, switch, this, throw
// true, try, type, using, var, view, virtual, weeks, wei, while
// years

3.2 关键字分类 #

声明类关键字:

关键字 用途 示例
contract 声明合约 contract Foo {}
interface 声明接口 interface IERC20 {}
library 声明库 library Math {}
struct 声明结构体 struct User {}
enum 声明枚举 enum Status {}
event 声明事件 event Transfer() {}
modifier 声明修饰器 modifier onlyOwner() {}

可见性关键字:

关键字 说明
public 公开,任何地方可访问
private 私有,仅本合约可访问
internal 内部,本合约及子合约可访问
external 外部,仅外部可调用

状态修饰关键字:

关键字 说明
view 只读,不修改状态
pure 纯函数,不读取也不修改状态
payable 可接收ETH

存储位置关键字:

关键字 说明
storage 永久存储
memory 临时内存
calldata 调用数据,只读

其他关键字:

关键字 用途
constructor 构造函数
fallback 回退函数
receive 接收函数
this 当前合约
super 父合约
import 导入文件
pragma 编译指示
using 库使用声明

四、代码规范 #

4.1 命名约定 #

合约命名:

solidity
// 使用大驼峰命名(PascalCase)
contract TokenVault {}
contract SimpleStorage {}
contract ERC20Token {}

函数命名:

solidity
// 使用小驼峰命名(camelCase)
function getBalance() public view returns (uint256) {}
function transferTokens() public {}
function calculateInterest() private pure returns (uint256) {}

变量命名:

solidity
// 状态变量:小驼峰,私有变量前加下划线
uint256 public totalSupply;
uint256 private _balance;
address internal _owner;

// 局部变量:小驼峰
function calculate() public {
    uint256 tempValue = 100;
    uint256 result = tempValue * 2;
}

// 常量:全大写下划线分隔
uint256 public constant MAX_SUPPLY = 1000000;
bytes32 public constant DOMAIN_SEPARATOR = keccak256("...");

事件命名:

solidity
// 使用大驼峰命名
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

修饰器命名:

solidity
// 使用小驼峰命名,表达限制条件
modifier onlyOwner() {
    require(msg.sender == owner, "Not owner");
    _;
}

modifier nonZeroAddress(address _addr) {
    require(_addr != address(0), "Zero address");
    _;
}

modifier whenNotPaused() {
    require(!paused, "Contract is paused");
    _;
}

4.2 代码布局 #

缩进:

solidity
// 使用4个空格缩进
contract Example {
    uint256 public value;
    
    function setValue(uint256 _value) public {
        value = _value;
    }
}

空行:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;  // 空行分隔声明


contract Example {       // 空行分隔合约
    uint256 public value1;
    uint256 public value2;  // 相关变量可不空行
    
    event ValueChanged(uint256 newValue);  // 空行分隔不同类型
    
    modifier validValue(uint256 _value) {
        require(_value > 0, "Invalid value");
        _;
    }
    
    function setValue(uint256 _value) public validValue(_value) {
        value1 = _value;
        emit ValueChanged(_value);
    }
    
    function getValue() public view returns (uint256) {
        return value1;
    }
}

行长度:

solidity
// 建议每行不超过120字符
// 长行可以换行
function veryLongFunctionName(
    address _token,
    address _recipient,
    uint256 _amount
) public returns (bool) {
    // 函数体
}

函数声明顺序:

solidity
contract OrderedContract {
    // 1. 状态变量
    uint256 public count;
    address public owner;
    
    // 2. 事件
    event CountChanged(uint256 newCount);
    
    // 3. 修饰器
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    // 4. 构造函数
    constructor() {
        owner = msg.sender;
    }
    
    // 5. 接收函数
    receive() external payable {}
    
    // 6. 回退函数
    fallback() external payable {}
    
    // 7. external函数
    function externalFunction() external {}
    
    // 8. public函数
    function publicFunction() public {}
    
    // 9. internal函数
    function internalFunction() internal {}
    
    // 10. private函数
    function privateFunction() private {}
}

4.3 最佳实践 #

1. 使用明确的可见性:

solidity
// 不推荐:省略可见性
function getValue() returns (uint256) {
    return value;
}

// 推荐:明确指定可见性
function getValue() public view returns (uint256) {
    return value;
}

2. 使用NatSpec文档:

solidity
// 推荐:添加文档注释
/**
 * @notice 转账代币给指定地址
 * @param to 接收地址
 * @param amount 转账数量
 * @return 是否成功
 */
function transfer(address to, uint256 amount) public returns (bool) {
    // 实现
}

3. 使用有意义的命名:

solidity
// 不推荐:无意义命名
function f(address a, uint256 x) public {}

// 推荐:有意义命名
function transferTo(address recipient, uint256 amount) public {}

4. 保持函数简洁:

solidity
// 推荐:单一职责
function setCount(uint256 newCount) public onlyOwner {
    count = newCount;
    emit CountChanged(newCount);
}

// 不推荐:函数过长
function doManyThings(uint256 a, uint256 b, uint256 c) public {
    // 100行代码...
}

五、表达式与语句 #

5.1 表达式 #

solidity
// 算术表达式
uint256 result = a + b * c;

// 比较表达式
bool isEqual = a == b;
bool isGreater = a > b;

// 逻辑表达式
bool isValid = isActive && hasPermission;
bool canProceed = !isPaused || isOwner;

// 位运算表达式
uint256 masked = value & mask;
uint256 shifted = value << 2;

5.2 语句 #

solidity
// 声明语句
uint256 value;
address owner;

// 赋值语句
value = 100;
owner = msg.sender;

// 表达式语句
value++;

// 块语句
{
    uint256 temp = value;
    value = temp * 2;
}

六、导入语句 #

6.1 导入方式 #

solidity
// 导入整个文件
import "./MyContract.sol";

// 导入并重命名
import * as MyLib from "./MyLib.sol";

// 导入特定符号
import {MyContract, MyStruct} from "./MyContract.sol";

// 从npm包导入
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

6.2 导入路径 #

solidity
// 相对路径
import "./SameDirectory.sol";
import "../ParentDirectory.sol";
import "./subdirectory/Child.sol";

// 绝对路径(从node_modules)
import "@openzeppelin/contracts/access/Ownable.sol";

七、总结 #

语法要点:

类别 要点
注释 单行//、多行/* */、NatSpec
标识符 字母、数字、下划线,不能以数字开头
关键字 保留字,不能用作标识符
命名 大驼峰(合约)、小驼峰(函数/变量)
可见性 public、private、internal、external

代码规范:

  • 使用有意义的命名
  • 添加NatSpec文档
  • 保持代码简洁
  • 遵循声明顺序

下一步,让我们学习Solidity的数据类型!

最后更新:2026-03-27