在Solidity中,引用类型(如structs、arrays和mappings)需要明确标注其存储位置。存储位置决定了数据的生命周期和可访问性。以下分了3种真实场景来介绍。
在 Solidity 中,引用类型(如 structs、arrays 和 mappings)需要明确标注其存储位置。存储位置决定了数据的生命周期和可访问性。以下分了3种场景来讨论:
在合约内但函数外声明的变量,默认使用 storage
且无法更改。这些变量是合约状态的一部分,会持久化存储在区块链上。
contract SimpleContract {
uint[] data; // 默认使用 storage
}
函数参数的存储位置可以是 memory
、calldata
或 storage
,具体选择取决于数据的使用方式和函数的可见性。
memory
contract SimpleContract {
function modifyMemoryArray(uint[] memory memory_a) public pure {
memory_a[0] = 0; // 可以修改 memory 数组的值
}
}
calldata
contract SimpleContract {
function modifyCalldataArray(uint[] calldata calldata_a) public pure {
// calldata_a[0] = 0; // 不能修改 calldata 数组的值,会报错
}
}
storage
storage
的函数可见性必须设置为 internal
或 private
。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 数组的值
}
}
在函数内部,可以使用 storage
或 memory
来声明变量,具体取决于数据的使用方式。
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
:用于只读的函数参数,主要用于 external
或 public
函数。通过合理标注存储位置,可以优化合约的性能(gas的优化)和安全性。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!