第3天.Storage、Memory、Calldata:数据到底放哪,为什么链上存储贵

2 阅读4分钟


第 1 题:什么是 storage?

参考答案:

storage 指的是 合约的永久状态存储区。

放在 storage 里的数据会真正记录在链上,并在多次调用之间持续保留。

常见场景:

  • owner 地址
  • 用户余额
  • 白名单
  • 是否已经领取过

一句话理解:

storage 是合约长期“记住”的东西。


第 2 题:什么是 memory?

参考答案:

memory 是 函数执行过程中的临时数据区域。

它只在当前这次函数调用中存在,调用结束后就没了,不会永久写到链上状态里。

常见场景:

  • 函数里的临时数组
  • 中间计算结果
  • 临时拼接的字符串

一句话理解:

memory 是函数运行时的临时工作台。


第 3 题:什么是 calldata?

参考答案:

calldata 是 外部调用传进来的参数区域,通常是只读的。

它常出现在 external 函数参数中,用来接收外部输入。

例如:

function addUsers(address[] calldata users) external { ... }

这里的 users 就属于 calldata。

一句话理解:

calldata 是别人传给合约的原始输入。


第 4 题:storage、memory、calldata 三者最大的区别是什么?

参考答案:

三者主要区别:

  1. 生命周期不同
    • storage:长期存在
    • memory:只在函数执行期间存在
    • calldata:只在外部调用参数里存在
  1. 用途不同
    • storage:保存永久状态
    • memory:做临时处理
    • calldata:接收外部输入
  1. 成本和特性不同
    • storage:最贵
    • memory:临时使用
    • calldata:常用于只读输入

一句话总结:

storage 管永久,memory 管临时,calldata 管输入。


第 5 题:为什么 storage 通常比 memory 和 calldata 更贵?

参考答案:

因为 storage 涉及的是 链上永久状态的写入和更新。

链上永久状态是整个网络都要维护的,所以成本更高。

对比:

  • memory:只是本次执行过程中的临时数据
  • calldata:只是外部传入的参数,不是永久状态

结论:

storage 贵,是因为它真正改变了链上的长期状态。


第 6 题:下面哪些数据更适合放在 storage?

题目选项:

  • owner 地址
  • 用户余额
  • 函数内部临时计算结果
  • 是否已领取
  • 白名单映射

参考答案:

适合放在 storage 的:

  • owner 地址
  • 用户余额
  • 是否已领取
  • 白名单映射

不适合放 storage 的:

  • 函数内部临时计算结果

**原因:**前面这些都需要长期保存,而临时计算结果不需要长期保留。


第 7 题:用户调用函数时传入的一组地址,通常更像 memory 还是 calldata?

参考答案:

通常更像 calldata。

因为这是 外部调用时传进来的原始参数。

如果函数是 external,这类输入通常会直接使用 calldata。

一句话理解:

外部传进来的输入,优先想到 calldata。


第 8 题:函数内部临时计算出来的奖励金额,通常更像 storage、memory 还是 calldata?

参考答案:

通常更像 memory 或临时变量。

因为它只是本次函数执行中的中间结果,不需要永久保存,也不是外部直接传进来的参数。

关键理解:

临时处理中间值,不应该默认放进 storage。


第 9 题:为什么很多 Web3 项目不会把所有数据都直接存在合约里?

参考答案:

链上存储成本高,尤其是 storage 的写入和更新代价高。

很多业务数据并不需要永久公开地保存到链上,比如:

  • 报表数据
  • 运营统计
  • 搜索索引
  • 缓存结果
  • 推荐数据

真实项目通常会把:

  • 关键规则、关键资产状态 放链上
  • 高频查询、复杂业务数据 放链下

一句话总结:

不是所有数据都值得占用昂贵的链上 storage。


第 10 题:请用一段完整的话,解释为什么合约开发里要区分 storage、memory 和 calldata。

参考答案:

因为这三种数据位置代表了不同的生命周期、用途和成本:

  • storage 用来保存合约的永久状态,会真正写入链上,因此最贵;
  • memory 用来存放函数执行过程中的临时数据,调用结束后就消失;
  • calldata 用来接收外部调用传入的参数,通常是只读的。

只有区分清楚这三者,才能正确设计合约数据结构并控制 Gas 成本。