摘要:本文介绍了 Soldiity 存储类型的区别。
Solidity 的数据有三种存储形式:storage
, memory
, calldata
.
它们的区别如下:
数据存储形式 | 生命周期 | 可修改性 |
---|---|---|
storage | 永久 | 可修改数值 |
memory | 函数结束 | 可修改数值 |
calldata | 函数结束 | 不可修改数值 |
也就是说:
- 当函数运行结束后,
storage
类型的数据会被保留,而memory
和calldata
类型的数据会被删除。 storage
和memory
类型的数据可以被修改,而calldata
类型的数据只可读不可写。
我们可以通过一个例子来理解区别:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
contract SimpleContract {
string public data;
// calldata 使用示例
function useData(string calldata _data) external {
// 该函数通过复制操作,进行存储类型的转换
// 从 calldata 类型的 _data 转换为了 storage 类型的 data
data = _data;
}
// memory 使用示例
function modifyData(string calldata _data) external pure returns (string memory) {
// 第一步,声明 memory 类型的变量 newData
// 再通过复制操作将 _data 的值存入到 newData 当中
string memory newData = _data;
// 第二步,在 newData 后添加 " modified" 字符串
// 要点1:abi.encodePacked(...) 是 Solidity 内置函数
// 它可以将字符串连接在一起,并以字节数组的形式返回
// 要点2:string(...) 用来将返回的字节数组转化为字符串形式
newData = string(abi.encodePacked(newData, " modified"));
// 第三步,返回修改过的 newData 数值
// 要点1:合约函数本身没有返回数值的能力
// EVM 会将 memory 类型的 newData 拷贝到返回数据缓存区中
// 然后在函数周期结束后删除 newData 的数据
// 要点2:calldata 无法被 EVM 放入返回数据缓存区中
// 这就是为什么 calldata 无法返回而 memory 可以返回
return newData;
}
}
通过以上例子我们可以看到:
calldata
类型的数据可以进行复制操作,可以将它的值复制到storage
和memory
类型的变量中。memory
类型的数据不仅可以进行复制操作,还可以被函数修改和返回。storage
类型的数据不仅可以进行以上操作,还可以函数运行结束后被调用。
在 Remix 中运行效果如下: