** storage、memory 和 calldata 是数据存储位置的关键概念,用于控制变量的存储方式和生命周期。**
1. Storage
-
功能: 用于链上持久化存储变量。变量存储在以太坊区块链的状态中,即合约的存储空间。
-
特点:
-
持久化,函数调用结束后仍然存在。
-
写入和读取成本较高(消耗较多 Gas)。
-
默认用于状态变量。
-
-
使用场景:
-
保存需要持久化的数据(如用户余额、合约状态等)。
-
定义合约级别的状态变量。
-
pragma solidity ^0.8.0;
contract StorageExample {
uint256 public storedValue; // 默认是 storage
function setValue(uint256 _value) public {
storedValue = _value; // 数据持久化存储在区块链上
}
function getValue() public view returns (uint256) {
return storedValue; // 从 storage 中读取
}
}
2. Memory
-
功能: 用于函数执行时的临时数据存储。变量只存在于函数调用期间,调用结束后被销毁。
-
特点:
-
非持久化,函数调用完成后即丢失。
-
读取和写入速度快,Gas 成本低。
-
常用于函数内部的局部变量。
-
-
使用场景:
-
函数中的临时计算。
-
传递或处理数据结构(如数组、字符串)。
-
pragma solidity ^0.8.0;
contract MemoryExample {
function multiply(uint256 a, uint256 b) public pure returns (uint256) {
uint256 result = a * b; // 局部变量存储在 memory 中
return result;
}
function reverseArray(uint256[] memory arr) public pure returns (uint256[] memory) {
uint256 len = arr.length;
uint256[] memory reversed = new uint256[](len); // 临时数组存储在 memory 中
for (uint256 i = 0; i < len; i++) {
reversed[i] = arr[len - 1 - i];
}
return reversed;
}
}
3. Calldata
-
功能: 专用于外部函数的输入参数。存储在调用数据中,变量只读且不可修改。
-
特点:
-
不可更改,只能读取。
-
Gas 成本最低,直接引用调用者提供的数据。
-
必须用于 external 函数的动态大小参数(如数组或字符串)。
-
-
使用场景:
-
外部函数接收用户输入的不可变数据。
-
提升效率,避免数据复制。
-
pragma solidity ^0.8.0;
contract CalldataExample {
function sumArray(uint256[] calldata arr) external pure returns (uint256) {
uint256 sum = 0;
for (uint256 i = 0; i < arr.length; i++) {
sum += arr[i]; // 直接从 calldata 中读取
}
return sum;
}
}
对比总结
实战示例:结合三者使用
pragma solidity ^0.8.0;
contract DataExample {
// 状态变量存储在 storage 中
uint256[] public storageArray;
// 添加元素到存储数组
function addToStorage(uint256 _value) public {
storageArray.push(_value); // 修改 storage,消耗较高 Gas。
}
// 处理临时数组数据
function processInMemory(uint256[] memory inputArray) public pure returns (uint256) {
uint256 sum = 0;
for (uint256 i = 0; i < inputArray.length; i++) {
sum += inputArray[i]; // 临时存储在 memory 中。
}
return sum;
}
// 外部调用传递不可变数据
function readFromCalldata(uint256[] calldata inputArray) external pure returns (uint256) {
return inputArray.length; // 直接读取 calldata,节省 Gas。
}
}
如何选择:
• storage:对于需要持久存储的数据(状态变量),必须使用。
• memory:在函数内部使用临时数据时,尤其是小型结构或数组。
• calldata:对于外部函数调用的大型数组或只读参数,使用 calldata 可以显著节省 Gas。
评论 (0)