(一)solidity基本语法规则

(一)solidity基本语法规则

viEcho Lv5

最近在玩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);
    }
    }
  • Title: (一)solidity基本语法规则
  • Author: viEcho
  • Created at : 2025-04-13 18:21:20
  • Updated at : 2025-05-11 16:34:55
  • Link: https://viecho.github.io/2025/0413/solidity-base-programming-rules.html
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments