24-Solidity8.0-存储位置(storage,memory 和 calldata)

785 阅读2分钟

存储在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 保存很小的局部变量,几乎免费使用,但有数量限制。