Solidity modifier 函数修改器
Solidity 中关键字 modifier 用于声明一个函数修改器。
我们可以将一些通用的操作提取出来,包装为函数修改器,来提高代码的复用性,改善编码效率。
函数修改器 modifier 的作用与 Java Spring 中的切面功能很相似,当它作用于一个函数上,可以在函数执行前或后预先执行 modifier 中的逻辑,以增强其功能。
函数修改器 modifier 常用于在函数执行前检查某种前置条件。
函数修改器 modifier 是一种合约属性,可被继承,同时还可被派生的合约重写(override)。
1. 基本函数修改器
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ModifierTest {
bool public paused;
uint public counter;
function setPaused(bool _paused) external {
paused = _paused;
}
modifier isNotPaused() {
require(!paused); // 检查前置条件:判断paused是否被设置,如果paused为true,那么终止执行。
_; // 执行被isNotPaused修饰的函数
}
function add() external isNotPaused{
counter++;
}
}
add函数被修改器isNotPaused修饰,所以先执行 require(!paused),检查前置条件,然后再执行add函数的代码。
2. _ 的作用
函数修改器中有一行代码只有下划线 _ ,我们认为下划线 _ 代表了被修饰函数的代码。
也就是说,下划线实际上帮我们标记了被 modifier 修饰函数的执行位置。如上例中:
modifier isNotPaused() {
require(!paused); // 检查前置条件:判断paused是否被设置,如果paused为true,那么终止执行。
_; // 执行被isNotPaused修饰的函数
}
下划线 _在 require(!paused) 后面,则被修饰函数 add 在此判断条件之后执行。
3. 带参数的函数修改器
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ModifierTest {
bool public paused;
uint public counter;
function setPaused(bool _paused) external {
paused = _paused;
}
modifier isNotPaused(uint x) {
require(x > 10 ); // 检查前置条件:判断x是否大于10,如果x大于或者等于10,那么终止执行。
_; // 执行被isNotPaused修饰的函数
}
function add(uint x) external isNotPaused(x){
counter++;
}
}
4. 复杂示例
我们来看一个函数修改器经典的应用 OpenZeppelin 库中的 Ownable 合约,下面是其中关键的代码:
/// Ownable 可以判断合约的调用者是否为当前合约的owner,
/// 从而避免其他人随意的调用一些合约的关键操作。
/// 同时,owner 可以指定任何其他人为此合约新的 owner,
/// 显然,只有当前owner才能指定其他人为新的owner。
contract Ownable {
// 变量 owner 指定此合约的owner
address public owner;
// 发布事件 - 此合约owner已经换人(此逻辑与modifier无关,可以忽略)
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
// 构造函数 - 创建合约自动执行,初始化合约所有人为合约创建者
function Ownable() public {
owner = msg.sender;
}
// 定义一个函数修改器
modifier onlyOwner() {
// 判断此函数调用者是否为owner
require(msg.sender == owner);
_;
}
// owner可以用此函数将owner所有权转换给其他人,显然次函数只有owner才能调用
// 函数末尾加上onlyOwner声明,onlyOwner正是上面定义的modifier
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
上述合约的 transferOwnership 函数用于 owner 将所有权转让给其他人,于是在末尾声明 onlyOwner 修改器,onlyOwner 将在 transferOwnership 执行前,先执行
require(msg.sender == owner);
以保证此函数的调用者为 owner ,如果不是 owner 则抛出异常。
下一章:Solidity 函数重载
Solidity的函数重载,是指同一个作用域内,相同函数名可以定义多个函数。这些函数的参数(参数类型或参数数量)必须不一样。仅仅是返回值不一样是不被允许。下面的例子展示了Solidity中的函数重载概念。示例// ...
AI 中文社