存储在storage上的是状态变量,storage变量永久存储在区块链上
memory上的是局部变量,memory变量则是临时的,当函数调用完成时被移除
calldata 和 memory比较类似,用在external函数调用中。
函数参数(包含返回的参数)默认是memory。
局部复杂类型变量(local variables)和 状态变量(state variables) 默认是storage。
calldata,用来存储函数参数,是只读的,不会永久存储的一个数据位置。外部函数的参数(不包括返回参数)被强制指定为calldata。效果与memory差不多。
数据位置指定非常重要,因为他们影响着赋值行为。
在memory和storage之间或与状态变量之间相互赋值,总是会创建一个完全独立的拷贝。
而将一个storage的状态变量,赋值给一个storage的局部变量,是通过引用传递。所以对于局部变量的修改,同时修改关联的状态变量。
另一方面,将一个memory的引用类型赋值给另一个memory的引用,不会创建拷贝(即:memory之间是引用传递)。
storage 存储结构是在合约创建的时候就确定好了的,它取决于合约所声明状态变量。但是内容可以被(交易)调用改变。
memory 只能用于函数内部,memory 声明用来告知EVM在运行时创建一块(固定大小)内存区域给变量使用。
pragma solidity ^0.8.7;
contract DataLocations {
struct MyStruct{
uint foo;
string text;
}
mapping(address => MyStruct) public myStructs;
function examples(uint[] calldata y, string calldata s) external returns (uint[] memory){
myStructs[msg.sender] = MyStruct({foo: 123, text:"bar"});
MyStruct storage myStruct = myStructs[msg.sender];
myStruct.text = "foo";
MyStruct memory readOnly = myStructs[msg.sender];
readOnly.foo = 456;
_internal(y);
uint [] memory memArr = new uint[](3);
memArr[0] = 234;
return memArr;
}
function _internal(uint[] calldata y) private {
uint x = y[0];
}
}
- storage 会永久保存合约状态变量,开销最大
- memory 仅保存临时变量,函数调用之后释放,开销很小
- calldata 保存很小的局部变量,几乎免费使用,但有数量限制。