概念
在 Solidity 中,状态变量 指合约中所有存储在区块链上的变量,定义在合约之内,函数之外。局部变量则是定义在函数之内。
Solidity 函数调用有两种方式:
- 内部调用(jump):像普通函数调用,参数用内存指针传递。
- 外部调用(EVM message call):通过 calldata 传递数据。
external 函数只支持外部调用,编译器知道参数只来自 calldata,所以可以直接读取 calldata 中的数据,不需要拷贝 → 节省 gas。
public 函数必须支持两种调用方式,所以编译器会强制把参数(尤其是数组、string、bytes)拷贝到 memory(即使是从外部调用也拷贝),这会产生 gas 开销。
solidity 有一些俗成的约定,会使用下划线 _ 区分状态变量和局部变量或者函数是否应该被外部调用,比如构造函数内部:
|
|
数据类型
值类型
-
bool:true | false
-
int、uint:整数类型,后面可以加数字,步长是 8,从 int8、uint8 到 int256、uint256,省略数字则默认 256。
-
address:地址类型,仅能存储 20 字节的地址。
-
address payable:可接收 ETH,有 .transfer() 和 .send() 方法,如:
1 2 3 4 5 6 7 8address addr = 0xAbC...; address payable payableAddr = payable(addr); // 转换为 payable //属性: addr.balance 该地址的ETH余额,单位是wei addr.code 合约字节码(bytes memory),若为 EOA 则为空 addr.code.length 判断是否为合约(>0 表示是合约) addr.codehash 合约代码的 keccak256 哈希(bytes32) -
bytes:定长字节数组,从 bytes1 到 bytes32,支持索引,有长度。
-
enum:枚举类型,按定义顺序从 0 开始自动分配整数值。
1 2 3 4enum Status { Pending, Approved, Rejected } // Pending → 0 // Approved → 1 // Rejected → 2
引用类型
引用类型使用时都需要加上 storage、memory 或 calldata。
storage:持久化存储在区块链上(合约状态变量)
memory:临时存储在内存,只在函数执行期间存在,函数结束即销毁。适合临时数据,gas 消耗较低。(函数内部使用)
calldata:只读的调用数据,通常用于外部函数参数,从交易数据中读取,不分配新内存,节省 gas。但构造函数参数不能使用 calldata
-
Array:数组,分为定长数组和动态数组,比如 int[5]和 int[ ]
-
struct:结构体
1 2 3 4struct Person { string name; uint age; } -
mapping:映射,也就是哈希 map,仅能声明为 storge,只能声明在合约顶部,不能作为局部变量或函数出入参。key 只能是值类型,value 无限制,key 不存在时默认返回值是 0。mapping 没有长度,无法遍历,也不能作为函数参数传递。
-
string:动态长度的字符串,底层是 bytes,不支持索引,但是可以通过 bytes(string)转成 bytes 类型。
函数
构造函数
在合约部署时只执行一次,用于初始化状态变量(如设置所有者、初始参数等)。
特点:
-
只能有一个构造函数
-
不能有返回值
-
不能被外部调用
-
如果没有显示定义则有一个空的默认构造函数
从 Solidity 0.7.0 起,不再使用 function ContractName() 的方式定义构造函数,必须使用 constructor 关键字,如:
|
|
普通函数
|
|
view 修饰的函数
不修改区块链的状态,可被外部免费调用(不消耗 gas)
|
|
pure 修饰的函数
既不读也不写区块链的状态,完全依赖参数计算
|
|
fallback 函数
当合约收到无 calldata 的调用或调用了不存在的函数时触发
|
|
receive 函数
仅当合约通过普通转账(非函数调用)收到 ETH 时触发
|
|
modifier(修饰器)
用于复用校验逻辑(如权限控制)
|
|
关键字
-
external:函数可见性修饰符之一,主要用于声明这个函数只能从合约外部调用,比如通过交易、其他合约调用或者 this.functionName(),不能直接 functionName() 调用,更省 gas!
-
public:可以直接 functionName()调用。
一些全局变量
- msg:一个内置的全局结构体(struct),由以太坊虚拟机(EVM)在每次外部调用时自动提供,无需声明或初始化,在任何函数中都可以直接访问,它包含了当前函数调用的上下文信息。

- block:提供当前区块的信息

ABI 接口
Application Binary Interface,应用二进制接口。相当于接口说明书,java 的 swagger 文档,json 格式,包含了:
- 这个合约有哪些可调用的函数?
- 每个函数的名字、参数类型、返回值类型是什么?
- 还有哪些事件(Events)、错误(Errors)可以被触发或抛出?
为什么需要 ABI?
智能合约部署到链上后,EVM(以太坊虚拟机)只认识字节码(bytecode),是一串十六进制字符串(人类完全看不懂),ABI 解决了这个问题,可以编码把人类可读的函数调用(如 transfer(address to, uint amount))转成 EVM 能懂的二进制数据,可以解码把合约返回的二进制数据转回人类可读的结果。
|
|