modifier即函数的修改器,可以用来改变一个函数的行为,控制函数的逻辑。修改器是一种合约属性,可以被继承和重写。
1.函数修改器
下面以代码为例进行介绍(代码来源于CryptoKitties项目KittyAccessControl.sol合约,详细代码可以查看https://github.com/dapperlabs/cryptokitties-bounty)
1 | modifier onlyCLevel() { |
前面一段代码是一个修改器,声明了一个约束onlyClevel:仅当当前的地址为ceoAddress或者cfoAddress或者cooAddress时,可以执行后续代码。下划线_是一个占位符,代表了执行函数接下来的代码。
有时你还会看到上面那段代码写成如下形式:
1 | modifier onlyCLevel() { |
其实两段代码是等价的,if() throw的写法是较为老式的写法,现在使用require()的写法较多。
1 | function pause() external onlyClevel whenNotPaused { |
接下来一段代码声明了一个函数pause(),用于暂停合约,这里使用了onlyClevel约束,表明该函数的执行必须要满足onlyClevel条件。
此外函数修改器也支持传入参数,和函数的参数类似,例如:
1 | pragma solidity ^0.4.0; |
在上面这段代码中,修改器lowerLimit传入两个参数,执行修改器的逻辑。函数的执行与否取决于两个参数:_withdraw和_balance。
函数的修改器参数支持表达式,例如:
1 | pragma solidity ^0.4.0; |
对于上面的这段代码,修改器m的参数传入了一个表达式:add(a+b),add()表达式在合约中定义了。
Return用在函数中表示返回值,如果函数有返回值标志return,但是由于修改器限制,判断不成功,无法执行函数体内的代码,那么将会返回返回值类型的默认值,例如:
1 | pragma solidity ^0.4.0; |
对于上面的代码,由于修改器A永远判断不成功,所以uintReturn和stringReturn两个函数的函数体永远无法执行,那么返回值分别是uint和string的默认值:0和空串。
函数修改器允许使用return;来中断当前流程,但是不允许明确的return值,也就是说在修改器中只能存在return;
对于函数修改器,下划线代表函数体,当执行到下划线;这一行的时候,就跳到函数体,执行函数体内的语句,执行完函数体内语句其实还要回到函数修改器,执行下划线_;后面的语句,例如:
1 | pragma solidity ^0.4.0; |
对于上面的函数f(),先运行修改器,判断权限,通过权限,则执行修改器判断语句后面的代码:map[true] = 1;,当运行到下划线;这一行的时候,跳到函数体内执行map[true] = 2;,然后retrun map[true]的值。执行完函数体的代码会回到函数修改器下划线;这一行后面的代码,这里还有代码,接着执行map[true] = 3。所以最终map[true]的值为3。
对于一个函数可以有多个修改器限制,在函数定义的时候依次写上,并用加空格分隔,执行的时候也是依次执行。多个修改器是同时限制,也就是说必须满足所有修改器的权限,才可以执行函数体的代码,例如:
1 | pragma solidity ^0.4.0; |
上面这段代码中两个修改器onlyOwner和inState同时作用于函数f(),只有当两个修改器的权限同时满足的时候,才会执行函数体内的代码,retrun 1。
2.重写修改器
我们知道合约是可以继承的,在子合约中我们还可以对父合约中的修改器进行重写覆盖,例如:
1 | pragma solidity ^0.4.0; |
上面这段代码中,子合约ModifierOverride继承了父合约bank,那么同样有父合约中的transferLimit修改器,之后在子合约中再次定义transferLimit修改器,就重写了该修改器并覆盖了原修改器,在子合约中transferLimit的限制条件由子合约中重写的条件决定。
Never regret a day in your life, good days give you happiness, bad days give you experiences.
书山有路勤为径,学海无涯苦作舟。
欢迎关注微信公众号:【程序员写书】
喜欢宠物的朋友可以关注:【电巴克宠物Pets】
一起学习,一起进步。
