Lazy loaded image
技术分享
solidity学习实录(长期更新)
Words 2164Read Time 6 min
2025-9-10
2025-9-17
type
status
date
slug
summary
tags
category
icon
password

🚩 uint

在 solidity 中,uint 是 uint256 的别称。如果只写 uint,那么编译器会把它理解为 uint256。
uint256 的取值范围是 0~2^256-1。
在以太坊虚拟机 EVM 中,uint256 是最高效的类型之一,因为 EVM 以 256 位(32 字节)为单位操作数据。使用更小的类型,在某些情况下可能不会节省 Gas,因为 EVM 仍会将其填充到 32 字节。

🚩 solidity 中变量的存储方式

在 solidity 中,变量的存储方式一共有 3 种:
1️⃣:storage(存储)
  • 永久存储在链上
  • 状态变量默认存储在storage中
  • 修改storage会消耗较多的 gas(因为这样会永久改变区块链状态)
2️⃣:memory(内存)
  • 临时存储,仅在函数执行期间存在
  • 函数参数和局部变量默认使用 memory
  • 操作 memory 消耗的 gas 较少
3️⃣:calldata
  • 类似于 memory,但是专门用于函数参数
  • 不可修改 immutable
  • 通常用于外部函数调用的参数

🚩 动态数组的优势

动态数组可以灵活的存储和管理结构化数据,相比单独声明多个变量,使用数组更节省存储空间,从而节省 gas

🚩 函数内的变量

习惯上,函数里的变量都用_作为开头,用来区分全局变量,但也不是硬性规定。

🚩 solidity 的函数修饰符

函数的修饰符用于控制函数的可见性和行为,主要是下面的几种:
  1. 可见性修饰符
      • public:函数可以被外部合约、内部合约和外部交易调用
      • private:函数只能在合约内部调用,子合约和外部合约均无法访问,习惯性的在 private 函数名字前面加上_
      • internal:函数可以在当前合约和继承它的子合约中调用,但外部合约无法调用
      • external:函数只能被外部合约或交易调用,不能在当前合约内部直接调用(除非使用 this.funcName( ))
      为了安全性,优先使用 privateinternal,仅在需要的时候开放为 publicexternal
  1. 状态可变性修饰符
      • view:函数承诺不会修改状态(仅读取数据)
      • pure:函数承诺既不读取也不修改状态(仅计算)
      • payable:函数可以接受 ETH(默认情况下函数会拒绝 ETH)
  1. 其他修饰符
      • virtual:允许函数在子合约中被重写(用于继承)
      • override:表示函数重写了父合约中的虚函数

🚩 msg.sender

在 solidity 中,功能执行始终需要从外部调用者开始。一个合约只会在区块链上什么都不做,除非有人从外部调用其中的函数。所以,msg.sender 总是存在的。

🚩 接口

接口的核心思想,接口定义【做什么】,合约实现【怎么做】:
  • 接口就像是功能说明书,只定义了有哪些函数
  • 接口本身不实现任何功能
  • 其他合约按照说明书来实现功能
接口的基本定义:
实现接口的合约:
接口的特性:
  • 只能声明函数,不能实现函数
  • 所有的函数都是 external,不能是private/public/internal
  • 不能定义状态变量
  • 不能定义构造函数

🚩 接口的简单调用示例

先定义一个简单的接口:
使用:
上面的这句代码可以这样理解:
  • NumberInterface 接口类型
  • numberContract 变量名称,是一个合约引用,是指向某个已部署合约的“指针”
  • NumberInterface(NumberInterfaceAddress) 这是关键部分,它做了3 件事:
      1. 类型转换,把address 类型转为NumberInterface 类型
      1. 合约绑定,告诉 solidity,这个地址对应的合约实现了NumberInterface 接口
      1. 创建引用,创建了一个可以调用目标合约函数的引用
  • numberContract = ... 把合约函数的引用存储到变量中,后续可以通过调用这个变量实现对目标合约函数的调用

🚩 字符串比较

在 solidity 中,比较字符串,需要比较他们的 keccak256哈希码:

🚩 关于 ABI

ABI 的全称是 Application Binary Interface,是智能合约的说明书,它定义了:
1️⃣ 如何与合约交互
  • 哪些函数可以调用
  • 每个函数需要什么参数
  • 函数会返回什么
2️⃣ 如何解析原始区块链数据
  • 如何解码交易输入数据
  • 如何解析事件日志
  • 如何理解合约状态
看几个示例:
  1. 函数调用
这个示例告诉 web3:
  • 调用函数 transfer 的时候,需要传递什么参数
  • 如何将这些参数编码成区块链能理解的二进制格式
  1. 事件解析
这个示例告诉 web3:
  • 如何识别区块链中的 Transfer 事件
  • 将二进制日志数据解码为可读格式
  1. 跨系统通信协议
  • 前端 DApp 与 区块链
  • 合约与合约
  • 开发工具与区块链
notion image
总结:ABI 是由 solidity 编译器产生的,连接人类可读代码和 EVM二进制世界,供所有需要与合约交互的系统使用。

🚩 智能协议的永固性

虽然 solidity 长得很像 JavaScript,但是DApp跟普通的 App 有着天壤之别。
当你把智能协议上传到以太坊之后,它就变得不可更改,这种永固性意味着你的代码永远不可能被调整和更新
你编译的程序会一直、永久的、不可更改的存在与以太坊上。
即便是你的智能协议有漏洞,你也没办法修补,只能让用户放弃这个协议,转移到新的协议上去。但这也是智能合约的一大优势,代码说明一切。

🚩 函数修饰符

修饰符是solidity 中非常重要的概念,它就像是给函数加上的“过滤器”或者是“插件”,可以在函数执行前后添加额外的逻辑。
solidity 中的主要修饰符有可见性修饰符、状态可变性修饰符、自定义修饰符。
可见性修饰符:
修饰符
通俗比喻
作用
public
公共区域
谁都可以访问
private
你的卧室
只有你可以进入
internal
你的家
只有你和家人可以进入
external
对外办事窗口
只有从外部可以进入
pure
心算
不需要任何外部信息
view
只看菜单但是不点菜
只获取信息
payable
收银台
可以收费
自定义修饰符
自己设置的检查制度
符合要求才能进入
自定义修饰符:
修饰符执行顺序,当多个修饰符叠加时,按照从右往左,从下到上的顺序执行:
自定义修饰符的最佳实践:
  • 语义化命名,onlyOwner比 check1 要好
  • 修饰符应该简洁,避免过长的逻辑
  • 谨慎使用后置逻辑,避免造成理解困难
  • 组合使用,多个简单修饰符组合比一个复杂的修饰符要好
🚨 常见错误
  • 遗忘_; 导致函数体永不执行
  • 修饰符顺序错误function test() payable onlyOwner {} ,这里应该把onlyOwner 放在前面
上一篇
solidity 优化 gas 的几个技巧
下一篇
中年程序员重学英语实录(长期更新)