14.DataLocations

Variables are declared as either storage, memory or calldata to explicitly specify the location of the data.

storage - variable is a state variable (store on blockchain) 永久存储在区块链中的变量

memory - variable is in memory and it exists while a function is being called 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。

calldata - special data location that contains function arguments

补充:

内存(memory)位置还包含2种类型的存储数据位置,一种是calldata,一种是栈(stack)。 calldata:这是一块只读的,且不会永久存储的位置,用来存储函数参数。

外部函数的参数(非返回参数)的数据位置被强制指定为 calldata ,效果跟 memory 差不多。

栈(stack):另外,EVM是一个基于栈的语言,栈实际是在内存(memory)的一个数据结构,每个栈元素占为256位,栈最大长度为1024。

值类型的局部变量是存储在栈上。

image-20230923160627037

storage: modify data

memory: read data

pragma solidity ^0.8.1;

contract DataLocation {
    struct MyStruct{
        uint foo;
        string text;
    }

    mapping (address=>MyStruct) public myStructs;

    function examples() external {
        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;
    }
}

storage的数值可以改

memory标记的,这个方法结束后,修改会被抹去

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;

contract SimpleStorage {
    string public text;

    function set(string calldata _text) external {
        text=_text;
    }

    function get() external view returns (string memory){
        return text;
    }
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract DataLocations {
    uint[] public arr;
    mapping(uint => address) map;
    struct MyStruct {
        uint foo;
    }
    mapping(uint => MyStruct) myStructs;

    function f() public {
        // call _f with state variables
        _f(arr, map, myStructs[1]);

        // get a struct from a mapping
        MyStruct storage myStruct = myStructs[1];
        // create a struct in memory
        MyStruct memory myMemStruct = MyStruct(0);
    }

    function _f(
        uint[] storage _arr,
        mapping(uint => address) storage _map,
        MyStruct storage _myStruct
    ) internal {
        // do something with storage variables
    }

    // You can return memory variables
    function g(uint[] memory _arr) public returns (uint[] memory) {
        // do something with memory array
    }

    function h(uint[] calldata _arr) external {
        // do something with calldata array
    }
}