跳转至

27存储位置

data location

  • storage:状态变量
  • memory:局部变量
  • calldata:和memory类似,但是只能用在函数输入的参数中

storage vs memory

storage从链上中读取数据并且修改

memory只能从链上读取数据,无法修改链上数据

// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;

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

    mapping (address=>MyStruct) public myStructs;

    function examples() external {
        myStructs[msg.sender]=MyStruct({
            foo:123,
            text:"bar"
        });

        // storage和memory区别
        // storage从链上中读取数据并且修改
        MyStruct storage mySturct=myStructs[msg.sender];
        mySturct.text="foo";

        // memory只能从链上读取数据,无法修改链上数据
        // 本次修改只在该函数内有效,对链上数据无影响
        MyStruct memory readOnly=myStructs[msg.sender];
        readOnly.foo=346;
    }
}

数组和string

内存的数据必须是定长。

动态数组只能用在状态变量和局部变量。

        // 数组array要标明存储位置,string也是一个特殊的数组
    function examples3(uint[]memory y, string memory s) external returns (uint[] memory){
        myStructs[msg.sender]=MyStruct({
            foo:123,
            text:"bar"
        });

        MyStruct storage mySturct=myStructs[msg.sender];
        mySturct.text="foo";

        MyStruct memory readOnly=myStructs[msg.sender];
        readOnly.foo=346;

        //定义数组
        uint [] memory memArr=new uint[](3);
        memArr[0]=234;
        return memArr;
    }

callable和memory

这种情况,调用_internal(params),calldata标注的话是直接传参进来

        // 数组array要标明存储位置,string也是一个特殊的数组
    function examples3(uint[]calldata y, string calldata s) external returns (uint[] memory){
        myStructs[msg.sender]=MyStruct({
            foo:123,
            text:"bar"
        });

        MyStruct storage mySturct=myStructs[msg.sender];
        mySturct.text="foo";

        MyStruct memory readOnly=myStructs[msg.sender];
        readOnly.foo=346;

        _internal(y);
        //定义数组
        uint [] memory memArr=new uint[](3);
        memArr[0]=234;
        return memArr;
    }

    function _internal(uint[] calldata y) private {
        uint x=y[0];
    }

如果是memory

会先拷贝一份所有的内容,很浪费gas(很多时候只需要单个参数)