Solidity中声明memory局部变量为何需函数为view类型?
Solidity中memory局部变量与view函数的关系解答
首先纠正一个常见误区:不存在「声明memory类型局部变量就必须将函数标记为view」的强制规则,两者没有绑定关系,你观察到的现象本质是Solidity的函数状态可变性校验规则和你写的代码逻辑刚好匹配。
先看你给出的示例代码:
contract PureMem{ uint[] public arr=[1,2,3,4]; function Mem() public view{ uint[] memory arrm=arr; arrm[1]=192; } }
搞懂这个问题先明确两个核心规则:
view是Solidity的函数状态可变性修饰符,标记为view的函数承诺不会修改任何存储在链上的合约状态,这类函数不需要发起链上交易、不需要消耗gas,节点本地模拟执行就能返回结果。如果函数内存在修改链上状态的操作,加view会直接编译失败。memory是EVM的临时内存区域,仅在函数调用期间临时分配空间,函数执行结束后内存就会被回收,所有对memory变量的修改都只在本次调用的生命周期内有效,根本不会写入链上的持久化存储。
回到你的代码逻辑:
- 你把存储在链上(storage区域)的状态变量
arr拷贝了一份到memory中,得到临时变量arrm,这一步仅涉及对链上状态的读取,没有写入 - 后续执行的
arrm[1]=192修改的是内存里的临时副本,和链上存的原始arr完全独立,不会对链上状态产生任何影响
整个函数全程只读取了链上状态、没有任何修改操作,完全符合view函数的约束,所以这里可以标记为view——注意是「可以」不是「必须」,你就算把view去掉,这段代码也能正常编译,只是编译器会提示你可以加view节省调用gas。
举个反例就能推翻错误认知:
function test() public { // 这里同样声明了memory类型的局部变量 uint[] memory tempArr = new uint[](3); tempArr[0] = 100; // 这一步修改了链上存储的状态变量 arr[2] = 999; }
这个函数里也用了memory局部变量,但因为存在修改链上状态的操作,绝对不能标记为view,否则编译器直接报错。
顺便提个新手常踩的坑:你这段代码里对arrm的修改是无效的,因为storage和memory之间的数组赋值是值拷贝,相当于复制了一份完全独立的备份,你改备份不会影响原数据,函数执行完内存释放,这个修改就彻底消失了。如果想要通过局部变量修改原数组,你需要声明storage类型的局部变量,而不是memory。
内容的提问来源于stack exchange,提问作者Hasnat Pie
相关产品推荐
相关产品推荐

