对solidity中的引用问题总是想再说说,再说说。前天直播讲了讲,感觉还不错,算是说明白了,在写几句话,总结的更精炼一些。
对于引用类型变量的赋值操作:
(相关资料图)
x = a
其实有两件事情要做:
1. 确定它的赋值语义:是引用拷贝还是值拷贝
2. 如果是值拷贝,检查它是否允许
这两个算法上次的文章讲过了。第一个算法供我们判断赋值操作干了什么事情,第二个算法让我们理解这个赋值操作没通过编译检查的原因。
对这两个算法我们今天再做一个辨析。
solidity的引用类型变量赋值被两个因素影响:
1. 其成员变量相比一般面向对象语言的对象的成员变量的特殊之处在于,java对象的成员变量在内存中,而合约的成员变量在持久化存储中,这使得合约成员变量的这个“引用”的含义发生了变化:它永远引用到固定的数据块。它不可能再去指向别的数据块。既然如此,当x是成员变量,只能是值拷贝操作。
2. 变量的location对赋值操作的影响是:它将其他语言中统一的数据存在空间分割成三个子空间(calldata memory storage),当赋值操作穿过子空间的边界,就必须是赋值操作了。具体的说,一种location的变量只能在一个子空间内切换指向不同数据块,但不能跑出这个子空间,跨子空间的赋值,也就是x和a的location不同时,必须、只能解释为赋值,这正是solidity编译器和evm运行时做的事情。
这是判定算法的完整解释。
检查算法是在判定算法完成,输出了结果之后执行的。如果判定为引用拷贝,那就不必检查了,因为检查的两件事情:calldata数据块只读和mapping不能遍历从而无法实现数据拷贝,在引用拷贝中都不会发生,所以没有检查的必要。
判定算法输出值拷贝时,关于calldata的检查是,x不能是calldata的。这不言而喻,因为你无法向message数据体的calldata数据域中拷东西,正如你不能修改msg.sender或msg.value。但值拷贝右侧的a是calldata没有问题。
判定算法输出值拷贝时,关于mapping的检查更严格:x和a的类型必须与mapping无关,即它本身不是mapping也不能嵌套拥有mapping的成分。mapping不能拷贝的原因不再赘述。
X 关闭
Copyright © 2015-2022 欧洲机械网版权所有 备案号:沪ICP备2022005074号-23 联系邮箱: 58 55 97 3@qq.com