Immutable
本节是《Solidity by Example》的中文翻译与深入讲解,专为零基础或刚接触区块链开发的小白朋友打造。我们将通过“示例 + 解说 + 提示”的方式,带你逐步理解每一段 Solidity 代码的实际用途与背后的逻辑。
Solidity 是以太坊等智能合约平台使用的主要编程语言,就像写网页要用 HTML 和 JavaScript,写智能合约就需要会 Solidity。
如果你从没写过区块链代码也没关系,只要你了解一点点编程概念,比如“变量”“函数”“条件判断”,我们就能从最简单的例子开始,一步步建立你的 Solidity 编程思维。
Immutable
不可变变量就像常量。不可变变量的值可以在构造函数中设置,但之后不能修改。
// SPDX-License-Identifier: MIT
// 声明代码采用 MIT 开源许可证,这是一种常见的开源许可协议,允许自由使用、修改和分发代码。pragma solidity ^0.8.26;
// 指定 Solidity 编译器版本必须大于或等于 0.8.26 并且小于 0.9.0。
// `pragma` 指令确保合约使用兼容的编译器版本,`^0.8.26` 表示支持 0.8.26 或更高版本(但不超过 0.9.0)。contract Immutable {// 定义一个名为 `Immutable` 的智能合约。// 合约是一个运行在以太坊区块链上的程序,包含数据(状态变量)和逻辑(函数)。// 这个合约的目的是展示 Solidity 中的不可变变量(immutable variables)。address public immutable myAddr;// 声明一个名为 `myAddr` 的不可变状态变量,类型为 `address`(以太坊地址,20 字节)。// `immutable` 关键字表示这个变量的值在合约部署时(通过构造函数)设置后不可修改。// `public` 关键字表示该变量可以被外部访问,Solidity 会自动为其生成一个 getter 函数(类似于 `function myAddr() public view returns (address)`)。// 未在声明时初始化,值将在构造函数中设置。uint256 public immutable myUint;// 声明一个名为 `myUint` 的不可变状态变量,类型为 `uint256`(256 位无符号整数,范围从 0 到 2^256-1)。// `immutable` 关键字表示这个变量的值在部署时设置后不可修改。// `public` 允许外部访问,并生成 getter 函数。// 未在声明时初始化,值将在构造函数中设置。constructor(uint256 _myUint) {// 定义一个构造函数(constructor),在合约部署时执行一次。// 构造函数接受一个参数 `_myUint`,类型为 `uint256`,用于初始化 `myUint`。// 构造函数是设置不可变变量值的唯一地方。myAddr = msg.sender;// 将 `myAddr` 设置为 `msg.sender`(全局变量,表示部署合约的账户地址)。// `msg.sender` 是调用构造函数的地址(通常是部署者的以太坊账户)。// 一旦设置,`myAddr` 不可再次修改。myUint = _myUint;// 将 `myUint` 设置为构造函数传入的参数 `_myUint`。// `_myUint` 是部署者提供的数值,设置后 `myUint` 不可再次修改。}
}
Immutable
是一个简单的智能合约,展示了 Solidity 中的不可变变量(immutable variables)。不可变变量类似于常量(constant
),但更灵活,因为它们的值可以在构造函数中动态设置,而常量必须在编译时硬编码。
代码做什么?
- 定义不可变变量:
myAddr
是一个不可变的以太坊地址,记录谁部署了这个合约(通过msg.sender
)。myUint
是一个不可变的数字,由部署者在构造函数中指定。
- 构造函数设置值:
- 在合约部署时,构造函数运行一次,设置
myAddr
和myUint
的值。 myAddr
被设置为部署者的地址(msg.sender
)。myUint
被设置为构造函数参数_myUint
的值。
- 在合约部署时,构造函数运行一次,设置
- 不可修改:设置后,
myAddr
和myUint
的值永久固定,无法再次更改。 - 公开访问:因为是
public
,外部可以通过 getter 函数读取这些变量的值(例如myAddr()
和myUint()
)。 - 节省 Gas:不可变变量比普通状态变量更节省 Gas,因为它们的值在部署后不会改变,编译器可以优化存储和访问。
关键点:
- 不可变变量的特点:
- 使用
immutable
关键字定义。 - 值在构造函数中设置,之后不可修改。
- 比普通状态变量更节省 Gas,因为编译器知道它们不会改变,可以优化存储。
- 使用
- 与常量的区别:
- 常量(
constant
):值在编译时硬编码(写死),不能在运行时动态设置。 - 不可变变量(
immutable
):值可以在构造函数中动态设置(例如基于msg.sender
或输入参数)。 - 例如,
myAddr
可以记录部署者的地址,而常量无法做到这一点。
- 常量(
- Gas 优化:
- 不可变变量的值在部署后固定,存储成本低于普通状态变量。
- 访问不可变变量(通过 getter 函数)是
view
操作,链下调用免费。
- 命名规范:
- 不可变变量没有强制的大写命名规范,但通常使用驼峰命名法(如
myAddr
、myUint
)。
- 不可变变量没有强制的大写命名规范,但通常使用驼峰命名法(如
- 状态变量:
myAddr
和myUint
是状态变量,存储在区块链的storage
中。public
提供了 getter 函数,方便外部读取。
- 用途:
- 不可变变量常用于存储部署时确定的值,例如:
- 部署者的地址(管理员地址)。
- 合约的初始化参数(最大限制、代币精度等)。
- 其他需要在部署时动态设置但之后不更改的值。
- 不可变变量常用于存储部署时确定的值,例如:
不可变变量的注意事项
- 不可修改:尝试修改不可变变量(如
myAddr = newAddress;
)会导致编译错误。 - 仅在构造函数中设置:不可变变量的值只能在构造函数中初始化,不能在其他函数中设置。
- 支持的类型:不可变变量支持值类型(如
uint256
、address
、bytes32
),但不支持复杂类型(如动态数组uint[]
或映射mapping
)。 - Gas 优化:不可变变量适合存储部署时确定的值,相比普通状态变量更节省 Gas。
- 与常量的对比:
constant
:值在编译时固定,适合硬编码的配置(如固定地址)。immutable
:值在部署时动态设置,适合依赖运行时数据的场景(如msg.sender
)。