(一)solidity基本语法规则
最近在玩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 | // 基类合约 |
4.关键规则总结
A.标准修饰符顺序:可见性 → 状态可变性 → 继承
B.状态访问限制函数禁止以下操作
1 | uint x = storageVar; // 禁止读取状态 |
C.多重继承需明确指定父合约
1 | contract Z is X, Y { |
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15contract 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);
}
} - 枚举 + 结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19contract 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;
}
} - 映射 + 动态数组(白名单管理)
1
2
3
4
5
6
7
8
9
10contract 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-11-29 19:33:07
- 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