(一)solidity基本语法规则

vvEcho 2025-11-29 19:33:07
Categories: Tags:

最近在玩solidity,所以记录一下solidity的一些语法规则

1、可见性修饰符

控制函数/变量的访问边界

修饰符 访问范围 典型场景
public 合约内外均可访问(自动生成状态变量的 getter 函数) 公开接口方法(balanceOf())
external 只能通过外部交易调用(合约内部不可直接调用) 回调函数(receive())
internal 仅限当前合约及继承合约(类似其他语言的 protected) 内部权限检查(_validate())
private 仅限当前合约内部(继承合约不可见) 敏感数据操作(_secretKey)

2、状态可变性修饰符

定义函数对链状态的读写权限

修饰符 状态交互规则 Gas 消耗 适用场景
pure 禁止读写状态变量和交易上下文 0 Gas 数学计算(sqrt(x))
view 只读状态变量(可访问 block.timestamp) 0 Gas 数据查询(getUserInfo())
payable 允许接收 ETH(msg.value) 按操作消耗 Gas 支付功能(deposit())

注意:
状态变量不加修饰符,默认为internal;在solidity > 0.5后,函数的声明必须加上修饰符

3、继承修饰符

管理合约继承体系中的函数覆盖

修饰符 作用规则 使用场景
virtual 标记函数可被子合约覆盖(基类函数必须声明) 可扩展的基类方法(_beforeTransfer())
override 声明函数覆盖父合约方法(需完全匹配父函数签名) 实现接口(IERC20.transfer())

继承示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 基类合约
contract Base {
// 可覆盖的基类方法
function calculate(uint a)
public
virtual
pure
returns (uint)
{
return a * 2;
}
}

// 子类合约
contract Child is Base {
// 正确顺序:public → pure → override
function calculate(uint b)
public
pure
override
returns (uint)
{
//调用父类方法
return super.calculate(b) + 10;
}
}

4.关键规则总结

A.标准修饰符顺序:可见性 → 状态可变性 → 继承

B.状态访问限制函数禁止以下操作

1
2
uint x = storageVar;       // 禁止读取状态
emit Transfer(msg.sender); // 禁止触发事件

C.多重继承需明确指定父合约

1
2
3
4
5
6
7
8
9
contract Z is X, Y {
// 最终覆盖函数必须包含所有父合约的 override 声明
function foo() public pure virtual override(X,Y) returns(string memory){
return "z";
}
function bar() public pure virtual override(X,Y) returns(string memory){
return "z";
}
}

5.存储位置

概念 控制权 读写权限 典型场景 是否消耗 Gas
storage 开发者 可读可写 合约状态变量 高(修改时)
memory 开发者 可读可写 函数内临时数据 低
calldata 开发者 只读 外部函数参数 最低
stack EVM 自动管理 局部变量和计算中间结果 低
logs 开发者 仅写入(emit) 事件日志记录 中
code EVM 只读 合约字节码存储 无

6.常用数据结构

数据结构 作用描述 典型使用场景
静态数组 固定长度的数组,元素类型和数量在声明时确定 存储固定数量的配置参数(如颜色代码、权限等级)
动态数组 长度可变的数组,支持动态添加或删除元素 管理用户列表、动态生成的数据集合(如投票记录、订单历史)
结构体(Struct) 自定义复合类型,可组合多个不同数据类型的字段 表示复杂实体(如用户信息、订单详情)、嵌套数据模型(如商品分类下的子分类)
映射(Mapping) 键值对存储结构,支持通过键快速查找值(但无法遍历键) 地址到余额的映射(mapping(address => uint))、唯一ID到实体的关联(如NFT)
枚举(Enum) 定义一组命名的常量集合,提升代码可读性 状态机标识(如订单状态:Created/Paid/Shipped)、用户角色分类
字符串(String) 存储UTF-8编码的文本数据 用户名、描述字段、日志消息(如错误提示)
字节数组(Bytes) 存储二进制数据(bytes为动态长度,bytes32为固定长度) 哈希值存储(bytes32)、加密消息、文件内容处理
合约类型(Contract) 引用其他合约地址,支持跨合约调用 代币合约交互(如IERC20(token).transfer())、可升级代理合约逻辑

注意
当函数参数涉及引用类型(如 string、array、struct)时,必须显式声明其数据位置(memory 或 calldata)
Solidity 0.5.0+ 版本严格要求所有引用类型参数必须明确数据位置,而旧版本允许隐式处理。若未指定,编译器会强制报错

7.组合使用场景示例

  1. 结构体 + 映射 + 动态数组
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    contract UserManager {
    struct User {
    address wallet;
    uint256 score;
    bool isActive;
    }

    mapping(address => User) private users; // 地址到用户的快速查找
    address[] public userList; // 遍历所有用户地址

    function addUser(address _wallet) public {
    users[_wallet] = User(_wallet, 0, true);
    userList.push(_wallet);
    }
    }
  2. 枚举 + 结构体
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    contract OrderSystem {
    enum OrderStatus {
    Created,
    Paid,
    Shipped
    }

    struct Order {
    uint256 id;
    address buyer;
    OrderStatus status;
    }

    Order[] public orders; // 动态数组存储订单

    function shipOrder(uint256 _id) public {
    orders[_id].status = OrderStatus.Shipped;
    }
    }
  3. 映射 + 动态数组(白名单管理)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    contract Whitelist {
    mapping(address => bool) public isWhitelisted;
    address[] public whitelistedAddresses; // 遍历白名单地址

    function addToWhitelist(address _addr) public {
    require(!isWhitelisted[_addr], "Already whitelisted");
    isWhitelisted[_addr] = true;
    whitelistedAddresses.push(_addr);
    }
    }