Solidity: 引用类型的储存位置: Storage, Memory, Calldata.

  • Aze
  • 更新于 2024-07-08 15:16
  • 阅读 800

在Solidity中,引用类型(如structs、arrays和mappings)需要明确标注其存储位置。存储位置决定了数据的生命周期和可访问性。以下分了3种真实场景来介绍。

在 Solidity 中,引用类型(如 structs、arrays 和 mappings)需要明确标注其存储位置。存储位置决定了数据的生命周期和可访问性。以下分了3种场景来讨论:

1. 合约内 函数外

在合约内但函数外声明的变量,默认使用 storage 且无法更改。这些变量是合约状态的一部分,会持久化存储在区块链上。

contract SimpleContract {
    uint[] data; // 默认使用 storage
}

2. 函数参数的存储位置

函数参数的存储位置可以是 memorycalldatastorage,具体选择取决于数据的使用方式和函数的可见性。

memory

  • 传入的参数被copy到了内存中且可以被修改。
  • 对函数可见性没有要求。
contract SimpleContract {
    function modifyMemoryArray(uint[] memory memory_a) public pure {
        memory_a[0] = 0; // 可以修改 memory 数组的值
    }
}

calldata

  • 传入的参数没有被copy到内存中, 是只读的,不能修改 。
  • 对函数可见性没有要求。(0.6.9版本以上)
contract SimpleContract {
    function modifyCalldataArray(uint[] calldata calldata_a) public pure {
        // calldata_a[0] = 0; // 不能修改 calldata 数组的值,会报错
    }
}

storage

  • 传入的参数只是传递了参数的引用,可以修改,并会影响原有变量。
  • 使用 storage 的函数可见性必须设置为 internalprivate
contract SimpleContract {
    uint[] storage_a  = [1, 2, 3];
    function f1() public {
    modifyStorageArray(storage_a ); // 直接传递了这个数组的引用
    }
    function modifyStorageArray(uint[] storage storage_a) internal {
        storage_a[0] = 0; // 可以修改 storage 数组的值
    }
}

3. 函数内部的使用

在函数内部,可以使用 storagememory 来声明变量,具体取决于数据的使用方式。

storage

在函数内部使用 storage 时,本质上是创建了一个对合约状态变量的引用。修改 data 数组的值会影响原有变量。

contract SimpleContract {
    uint[] data = [1, 2, 3];

    function foo() public {
        uint[] storage dataRef = data; // 创建了一个对状态变量 data 的引用
        dataRef[0] = 10; // 修改 data 数组的值
    }
}

memory

在函数内部使用 memory 时,是创建一个新的内存数组,其生命周期仅限于函数执行期间。修改 memory 数组的值,不会影响原有变量。

contract SimpleContract {
    function foo() public {
        uint[] memory tempData = new uint[](10); // 创建一个新的 memory 数组
        tempData[0] = 1; // 修改 memory 数组的值
    }
}

总结

  • storage:用于持久化存储在合约状态中的数据,函数参数和函数内部变量都可以使用,需注意其函数可见性限制。
  • memory:用于临时存储在函数执行期间的数据,函数参数和函数内部变量都可以使用,无特殊可见性限制。
  • calldata:用于只读的函数参数,主要用于 externalpublic 函数。

通过合理标注存储位置,可以优化合约的性能(gas的优化)和安全性。

参考资料

  1. Solidity Documentation - Data Location
  2. CSDN Blog - Solidity 数据存储位置
  3. Alchemy Documentation - When to Use Storage vs Memory vs Calldata in Solidity
  4. Ethereum Stack Exchange - In What Cases Would I Set a Parameter to Use Storage Instead of Memory?
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Aze
Aze
0x758e...1541
Long the bitcoin, short the world.