第 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 三者最大的区别是什么?
参考答案:
三者主要区别:
- 生命周期不同
-
- storage:长期存在
- memory:只在函数执行期间存在
- calldata:只在外部调用参数里存在
- 用途不同
-
- storage:保存永久状态
- memory:做临时处理
- calldata:接收外部输入
- 成本和特性不同
-
- 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 成本。