文章目录
-
- [Solidity 合约](#Solidity 合约)
- [Solidity 合约结构](#Solidity 合约结构)
-
- 状态变量
- 函数
- 函数修饰符
- 事件
- 错误(Errors)
- [结构体类型(Struct Types)](#结构体类型(Struct Types))
- [枚举类型(Enum Types)](#枚举类型(Enum Types))

Solidity 合约
Solidity 中的合约类似于面向对象语言中的类。每个合约可以包含状态变量、函数、函数修饰符、事件、错误、结构体类型和枚举类型。此外,合约可以继承自其他合约。
还有一些特殊类型的合约,称为库(libraries)和接口(interfaces)。
Solidity 合约结构
本文针对合约结构提供一个快速概览。
状态变量
状态变量是那些值被永久存储在合约存储中的变量,或者是临时存储在瞬态存储中的变量,后者在每次交易结束时会被清除。
solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
contract SimpleStorage {
uint storedData; // 状态变量
// ...
}
函数
函数是代码的可执行单元。函数通常定义在合约内,但也可以在合约外部定义。
solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.1 <0.9.0;
contract SimpleAuction {
function bid() public payable { // 函数
// ...
}
}
// 在合约外部定义的辅助函数
function helper(uint x) pure returns (uint) {
return x * 2;
}
函数调用可以是内部的或外部的,并且具有不同的可见性级别。函数接受参数并返回变量,以便在它们之间传递数据和值。
函数修饰符
函数修饰符可用于以声明方式修改函数的语义。
特点
1.不支持重载,即不能使用相同名称但不同参数的修饰符。
2.与函数类似,修饰符可以被重写。
以下示例展示了 onlySeller 修饰符,该修饰符用于确保只有 seller(卖家)才能调用特定函数:
solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
contract Purchase {
address public seller;
modifier onlySeller() { // 定义修饰符
require(
msg.sender == seller,
"Only seller can call this."
);
_; // 继续执行被修饰的函数
}
function abort() public view onlySeller { // 使用修饰符
// 仅限卖家调用
}
}
事件
Solidity 事件(Events)是 EVM(以太坊虚拟机)提供的日志机制,用于在链上记录特定操作,并供外部应用监听和使用。
特点
1.相比状态变量存储,事件日志存储在交易日志中,成本更低。
2.便于外部访问,前端应用(如 dApps)可以监听事件,实时获取区块链上的重要信息。
3.不可被合约内部读取,合约代码无法直接访问已触发的事件信息(但可由外部应用监听)。
以下示例展示了 HighestBidIncreased 事件,该事件在 bid() 函数被调用时触发,并记录投标人和投标金额。
solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.22;
event HighestBidIncreased(address bidder, uint amount); // 事件
contract SimpleAuction {
function bid() public payable {
// ...
emit HighestBidIncreased(msg.sender, msg.value); // 触发事件
}
}
错误(Errors)
错误(Errors)允许为失败情况定义描述性名称和数据,通常通过 revert
语句实现。
特点
1.与直接使用字符串描述相比,错误的 gas 成本更低,并且可以编码额外数据。
2.可以使用 NatSpec 为用户提供错误的详细说明。
示例代码如下:
solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
/// 转账资金不足。请求金额为 `requested`,但仅有 `available` 可用。
error NotEnoughFunds(uint requested, uint available);
contract Token {
mapping(address => uint) balances;
function transfer(address to, uint amount) public {
uint balance = balances[msg.sender];
if (balance < amount)
revert NotEnoughFunds(amount, balance); // 触发错误
balances[msg.sender] -= amount;
balances[to] += amount;
// ...
}
}
结构体类型(Struct Types)
结构体(Structs)是自定义类型,可用于将多个变量组合在一起。
示例代码如下:
solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
contract Ballot {
// 定义一个名为 Voter(投票者)的结构体
struct Voter {
uint weight; // 该投票者的投票权重
bool voted; // 该投票者是否已经投票
address delegate; // 该投票者委托的代理人地址
uint vote; // 该投票者所投的候选人编号
}
}
枚举类型(Enum Types)
枚举(Enums)可用于创建一组预定义的 常量值,使代码更具可读性和可维护性。
特点:
1.用易理解的单词替代数字或布尔值,例如 State.Created 比 0 更直观。
2.枚举类型的变量只能取其定义的值,有助于减少错误。
3.Solidity 中的枚举本质上是 uint 类型,第一个成员默认值为 0,第二个成员 1,依此类推。
示例代码如下:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
contract Purchase {
// 定义一个枚举类型 State,表示合约的不同状态
enum State { Created, Locked, Inactive }
// 声明一个状态变量,默认值为 `State.Created`
State public currentState;
// 修改合约状态的方法
function setLocked() public {
currentState = State.Locked;
}
function setInactive() public {
currentState = State.Inactive;
}
}