solidity学习随记
Solidity 学习随记
本文集中记录 Solidity 函数可见性、状态可变性和数据位置。理解这三部分能够避免调用上下文混淆、状态误修改和不必要的 Gas 消耗。
函数可见性
| 可见性 | 合约内部调用 | 外部调用 | 典型用途 |
|---|---|---|---|
private |
仅当前合约 | 不允许 | 局部实现细节 |
internal |
当前合约与派生合约 | 不允许 | 可继承的内部逻辑 |
public |
允许 | 允许 | 同时服务内部与外部 |
external |
不能按函数名直接调用 | 允许 | 外部接口入口 |
external 的正确调用方式
同一合约中的 external 函数不能写成 operation() 进行内部调用。使用 this.operation() 可以调用,但它会经过 ABI 编码并执行一次 EVM 外部调用,msg.sender 也会变为当前合约地址。
1 | // SPDX-License-Identifier: MIT |
推荐做法是把可复用逻辑提取到 internal 函数,外部入口只负责权限、参数和业务边界校验。
1 | flowchart LR |
pure 与 view
pure函数不能读取或修改合约状态。view函数可以读取状态,但不能修改状态。- 普通函数可以读取和修改状态。
payable额外允许函数接收原生资产。
编译器会沿调用链检查状态可变性。一个函数即使没有直接赋值,只要调用的内部函数修改状态,它就不能声明为 view 或 pure。
memory、storage 与 calldata
storage表示链上持久化数据。局部storage变量通常是状态数据的引用。memory表示当前调用期间的临时数据,修改不会自动写回状态。calldata表示只读调用输入,适合external函数参数,通常可减少复制。
1 | contract DataLocationDemo { |
changeMemory 接收状态数组的副本,所以 values[3] 仍为 40。changeStorage 持有真实状态引用,所以 values[4] 变为 10。最终返回 40 和 10。
调用与交易的区别
对节点执行只读调用不会创建交易,也不消耗用户链上 Gas。发送修改状态的交易需要签名、广播、进入区块并成功执行。交易中的 Solidity 返回值通常不会直接出现在普通交易回执中,前端应使用事件、状态读取或交易模拟获得业务结果。
1 | sequenceDiagram |
常见错误
- 把
external入口当作可直接复用的内部函数。 - 使用
this自调用后忽略msg.sender和重入边界变化。 - 把
memory副本的修改误认为会写回状态。 - 为修改状态的函数错误添加
view或pure。 - 依赖交易返回值,而没有设计事件或状态查询接口。
- 对大数组进行不必要的
storage到memory复制。
设计建议
外部入口保持简短,把核心业务规则放入内部函数。明确每个参数的数据位置,对外部调用遵循先检查、再更新状态、最后交互的顺序。测试时同时覆盖直接外部调用、代理调用、合约自调用和内部函数复用路径。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 EIGHTJIU!
评论





