Solidity 数据位置(data location)
1. 引用类型/复合数据类型
Solidity中,有一些数据类型由简单数据类型组合而成,相比于简单的值类型,这些类型通常通过名称引用,被称为引用类型,
引用类型包括:
- 数组 (字符串与bytes是特殊的数组,所以也是引用类型)
- struct (结构体)
- map (映射)
这些类型涉及到的数据量较大,复制它们可能要消耗大量Gas,非常昂贵,所以使用它们时,必须考虑存储位置。例如,是保存在内存中,还是在 EVM 存储区中。
2. 数据位置(data location)
在合约中声明和使用的变量都有一个数据位置,指明变量值应该存储在哪里。合约变量的数据位置将会影响Gas消耗量。
Solidity 提供 3 种类型的数据位置。
- storage
- memory
- calldata
1) storage
存储位置 storage 用来存储永久数据,可以被合约中的所有函数访问。
storage 变量,通常用于存储智能合约的状态变量,它在函数调用之间保持持久性。
storage 与其他数据位置相比,成本较高。
我们可以把它理解为计算机的硬盘数据,所有数据都永久存储。
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SoldityTest { struct MyData { uint id; string value; } MyData[] public myData; constructor(){ myData.push(MyData(1, "value1")); myData.push(MyData(2, "value2")); } function operations() external{ // storage 存储位置 MyData storage d = myData[0]; // 修改状态变量myData的内容 d.value = "new value"; } }
合约 SoldityTest 部署后,调用 operations 方法,状态变量 myData 的数据被修改,其中 myData[0].value 变为 "new value"。
2) memory
存储位置 memory 用来存储临时数据,比 storage 便宜。
memory 变量,通常用于保存临时变量,以便在函数执行期间进行计算。一旦函数执行完毕,它的内容就会被丢弃。它只能在所在的函数中访问。
我们可以把它理解为每个单独函数的内存 RAM。
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SoldityTest { struct MyData { uint id; string value; } MyData[] public myData; constructor(){ myData.push(MyData(1, "value1")); myData.push(MyData(2, "value2")); } function operations() external{ // memory 存储位置 MyData memory d = myData[0]; // 修改状态变量myData的内容 d.value = "new value"; } }
合约 SoldityTest 部署后,调用 operations 方法,状态变量 myData 的数据未被修改,其中 myData[0].value 仍然为 "value1"。
3) calldata
calldata 是不可修改的非持久性数据位置,类似于 memory,但只能出现在函数的输入参数位置。
外部函数 external function 的传入参数强制为 calldata 类型。
使用 calldata 的好处是在内部函数中作为输入参数传递时,省掉了数据拷贝的成本,节省 gas 费。memory 作为参数时,需要进行数据拷贝。
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SoldityTest { function operations(string calldata val) pure external{ // 使用 calldata 传递参数,省却复制成本 internalFunc1(val); // 使用 memory 传递参数,需要进行复制 internalFunc2(val); } function internalFunc1(string calldata val) internal pure { // ...... } function internalFunc2(string memory val) internal pure { // ...... } }
下一章:Solidity 变量的数据位置规则
1. 规则1 – 状态变量状态变量总是存储在存储区中。// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract ...