【从0学习Solidity】变量初始值
发布时间:2025-08-29 00:10       
下面这一篇把 Solidity 中“变量初始值” 讲清楚:哪些会被自动置零、哪些必须先赋值、delete 如何复位,以及数组/映射/结构体/枚举的细节。适合从 0 起步的你一次掌握 ✅。
一句话概念
在 Solidity(0.8.x 主线)里:状态变量(storage)默认零值;函数内局部变量不能读未赋值;用 new 创建的 memory 动态数组会被零填充;delete 会把目标还原到其类型的默认值。🙂
规则总览表(精炼版)
| 场景/类型 | 初始值/行为 | 说明 |
|---|---|---|
uint / int(storage) |
0 |
有符号/无符号皆为 0 |
bool(storage) |
false |
布尔默认假 |
address/address payable |
address(0)/payable(address(0)) |
全 0 地址 |
bytes32/定长 bytesN |
全 0 | 定长字节均置零 |
string/ 动态 bytes(storage) |
空串 / 长度 0 | 不占用额外数据 |
| 固定长度数组(storage) | 每个元素置零 | 例:uint[3]→[0,0,0] |
| 动态数组(storage) | 长度 0 | 未 push 之前为空 |
mapping |
任意 key 返回“值类型默认值” | 读不存在 key 得默认值;不存在“键集合” |
struct(storage) |
各字段置零 | 递归地零初始化 |
enum(storage) |
枚举下标 0(第一个成员) |
如 enum S{A,B}默认 S.A |
| 局部标量(函数内) | 不能读未赋值 | 编译时报错 |
new T[](memory) |
元素全为 0 | 内存数组被零填充 |
calldata参数 |
由外部调用提供 | 无“默认值”概念 |
delete x |
还原为类型默认值 | 复位标量/数组/struct;delete m[k]仅清该键 |
必知细节与推理
- 为何状态变量会“自动为 0”?
EVM 语义:未写入的存储槽读取为 0。Solidity 的状态变量落在 storage 槽里,因此天然零初始化。这对结构体、固定数组是递归生效的,对动态数组则体现为长度 0。 - 为何函数里的局部变量必须先赋值?
为避免把“随机内存值”误当数据,编译器强制:局部变量读之前必须写。所以uint x; return x;会直接编译失败。🚫 memory动态数组如何初始化?
使用new uint[](n)时,编译器会零填充分配到的内存段(与 EVM 内存分配策略一致),因此每个元素起始为0。mapping为何读不到“未设置”和“真的为 0”的区别?
读不存在的键返回值类型默认值(如0/false/空结构),所以需通过配套布尔位或外部索引区分“是否曾写入”。enum默认值与安全性
默认是第一个枚举成员;若用底层写存储可能产生无效枚举值,读写时应做范围校验(常用于防御性编程)。delete的一致复位语义delete x:把x设为其类型默认值;delete arr[i]:只复位该元素,不改变数组长度;delete arr(动态数组):长度置 0;delete m[k]:仅清除该键的值为默认值;不能delete m(整个映射不可删除)。
- 常量与不可变量
constant:声明时必须赋值;immutable:需在声明或构造函数内一次性赋值;二者不存在默认值概念。
可直接验证的示例(Solidity ^0.8.x)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract DefaultValues {
enum Status { None, Active, Closed }
struct User { uint id; bool ok; address owner; }
// ---- storage 状态变量(自动零初始化)----
uint public a; // 0
bool public b; // false
address public c; // 0x000...0
bytes32 public d; // 0x0
string public s; // ""
uint[3] public fixedArr; // [0,0,0]
uint[] public dynArr; // length=0
mapping(address => uint) public bal; // 缺键返回 0
Status public st; // Status.None
User public u; // {id:0, ok:false, owner:0}
// ---- memory 动态数组被零填充 ----
function sumOfZeros(uint n) external pure returns (uint) {
uint[] memory arr = new uint[](n); // 全 0
uint ssum;
for (uint i; i < n; ) { ssum += arr[i]; unchecked{ ++i; } }
return ssum; // 恒为 0
}
// ---- delete 复位为默认值 ----
function resetA() external {
a = 5;
delete a; // a -> 0
}
// // 编译失败示例(请勿取消注释):
// function bad() external pure returns (uint) {
// uint x; // 未赋值
// return x; // ❌ 编译错误:读未赋值的局部变量
// }
}
要点解读
- 所有
public状态变量在部署后立刻可读