news 2026/9/15 13:00:58

WTF-Solidity 极简入门:Solidity 状态变量只读化——constant 与 immutable 关键字完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WTF-Solidity 极简入门:Solidity 状态变量只读化——constant 与 immutable 关键字完整指南

WTF-Solidity 极简入门:Solidity 状态变量只读化——constant 与 immutable 关键字完整指南

【免费下载链接】WTF-SolidityWTF Solidity 极简入门教程,供小白们使用。Now supports English! 官网: https://wtf.academy项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-Solidity

constant(常量)与immutable(不变量)是 Solidity 中用于限制状态变量修改的两大关键字。本文以 WTF-Solidity 仓库西语教程 Languages/es/09_Constante_es/readme.md 为主体,结合仓库源码 Constant.sol 与主版本教程 09_Constant/readme.md,系统讲解二者的声明语法、初始化时机、类型适用范围与编译期约束,并给出可在 Remix 中逐条验证的实操步骤。学完本篇,你将能在自己的合约中准确选用constantimmutable来固化不应变更的状态,在提升合约安全性的同时节省gas

为什么需要 constant 与 immutable

在 Solidity 中,状态变量(state variable)默认是可写的,任何函数都能修改它们的数值。但合约中总有一类"一经确定就不该再变"的数据——例如协议版本号、零地址、上限额度等。如果放任其随意被修改,轻则造成逻辑混乱,重则成为安全漏洞。

constantimmutable正是为此而生的关键字:状态变量一旦以这两个关键字声明,其数值在编译/初始化完成后便无法再被修改。这种做法带来两方面的收益:

  • 提升合约安全性:将不应变化的数值在编译期"焊死",杜绝运行期被意外或恶意改写;
  • 节省gasconstantimmutable变量的值在编译期被内联进字节码,读取时不走常规的storage存储槽访问路径,因此比普通可写状态变量的读取更省gas

类型适用范围:不是所有类型都支持

在动手声明之前,需要先记住一个重要的类型限制:

  • 数值类型(value type)变量:既可以声明为constant,也可以声明为immutable
  • stringbytes类型变量:可以声明为constant,但不能声明为immutable

这一规则在教程原文中明确给出,也是 Solidity 语言层面的硬性约束。理解了适用范围,下面分别看两种关键字的用法。

constant 常量:声明时必须初始化

constant变量的规则最简单直接:必须在声明的同时完成初始化,初始化后任何时刻都不能再改变。一旦尝试修改,编译将直接不通过。

仓库源码 Constant.sol 给出了四个覆盖不同数据类型的示例:

// Una variable de tipo constante debe ser inicializada cuando es declarada, ya que después no se puede modificar // constant 变量必须在声明时初始化,之后不能改变 uint256 public constant CONSTANT_NUM = 10; string public constant CONSTANT_STRING = "0xAA"; bytes public constant CONSTANT_BYTES = "WTF"; address public constant CONSTANT_ADDRESS = 0x0000000000000000000000000000000000000000;

对照源码可以看到,四个变量在声明行内就完成了初始化:uint256数值、string字符串、bytes字节串以及address零地址各占一种类型,覆盖了最常见的常量使用场景。

如果声明之后试图给constant变量重新赋值,Solidity 编译器会抛出错误:

TypeError: Cannot assign to a constant variable.

这正是教程在 Remix 中的验证结论:constant变量一经初始化,任何后续赋值都是非法的,错误在编译阶段就会被拦截,而非等到部署运行后才暴露。

immutable 不变量:声明时或构造函数中初始化

immutable相比constant更加灵活:它既可以在声明时初始化,也可以在构造函数(constructor)中初始化。一旦初始化完成,其数值同样不可再变。

仓库源码 Constant.sol 中的示例同时用到了两种初始化方式:

// Las variables inmutables pueden ser inicializadas en el constructor y no se pueden modificar después // immutable 变量可以在构造函数中初始化,之后不能改变 uint256 public immutable IMMUTABLE_NUM = 9999999999; address public immutable IMMUTABLE_ADDRESS; uint256 public immutable IMMUTABLE_BLOCK; uint256 public immutable IMMUTABLE_TEST;

其中IMMUTABLE_NUM在声明时就被初始化为9999999999;而其余三个变量只在声明处留了"空位",等待构造函数赋值。

用全局变量或自定义函数初始化

immutable灵活性的另一体现是:它可以使用 Solidity 的全局变量(如address(this)block.number)甚至自定义函数来初始化。这使它能够捕获部署时刻的链上环境信息,而这在编译期是无法预知的。

源码 Constant.sol 的构造函数演示了三种初始化来源:

// Las variables inmutables son inicializadas en el constructor, por lo que se pueden usar en el resto del contrato // immutable 变量在构造函数中初始化,之后可在合约其余部分使用 constructor(){ IMMUTABLE_ADDRESS = address(this); IMMUTABLE_BLOCK = block.number; IMMUTABLE_TEST = test(); } function test() public pure returns(uint256){ uint256 what = 9; return(what); }
  • IMMUTABLE_ADDRESS = address(this);:把当前合约自身的地址固化下来;
  • IMMUTABLE_BLOCK = block.number;:记录合约部署时的区块号;
  • IMMUTABLE_TEST = test();:调用自定义的pure函数test(),将返回值9写入变量。

test()是一个pure函数,不读取也不修改状态,纯粹返回9,因此可以安全地在构造函数中调用。这种"用函数返回值初始化只读状态变量"的模式,在实际合约中常被用于将部署参数、时间戳等动态信息一次性地固化。

重复初始化的后果

如果immutable变量在声明处已初始化,又在构造函数中再次赋值(即"重复初始化"),编译器同样会拦截:

TypeError: Immutable state variable already initialized.

值得注意的是,主版本中文教程 09_Constant/readme.md 还补充了两条进阶规则(仓库内可验证):

  • immutable变量既在声明时初始化、又在构造函数中初始化,最终生效的是构造函数中初始化的值
  • Solidity v0.8.21 之后immutable变量不再要求显式初始化,未显式初始化的变量会采用数值类型的初始值(参见 08_InitialValue/readme.md 中关于变量初始值的讲解);反之,在更早版本中则需要显式初始化。

这两条规则对判断"最终读到什么值"至关重要,建议结合自己的编译器版本仔细核对。

完整源码对照

将上述片段组合起来,就是本讲完整的示例合约(西语版 Constant.sol,主版本 09_Constant/Constant.sol):

// SPDX-License-Identifier: MIT pragma solidity ^0.8.34; contract Constant { // constant 变量必须在声明时初始化,之后不能改变 uint256 public constant CONSTANT_NUM = 10; string public constant CONSTANT_STRING = "0xAA"; bytes public constant CONSTANT_BYTES = "WTF"; address public constant CONSTANT_ADDRESS = 0x0000000000000000000000000000000000000000; // immutable 变量可以在构造函数中初始化,之后不能改变 uint256 public immutable IMMUTABLE_NUM = 9999999999; address public immutable IMMUTABLE_ADDRESS; uint256 public immutable IMMUTABLE_BLOCK; uint256 public immutable IMMUTABLE_TEST; // immutable 变量在构造函数中初始化,因此可以在合约其余部分使用 constructor(){ IMMUTABLE_ADDRESS = address(this); IMMUTABLE_BLOCK = block.number; IMMUTABLE_TEST = test(); } function test() public pure returns(uint256){ uint256 what = 9; return(what); } }

两个目录下的.sol文件内容一致,均采用pragma solidity ^0.8.34编译指令。由于所有变量都以public声明,Solidity 会自动为它们生成同名的getter函数,方便在部署后直接读取。

说明:声明了public constant/public immutable的变量自动生成getter,这也是在 Remix 中可以直接点按查看数值的原因。

在 Remix 中验证(实操三步走)

教程原文给出了完整的 Remix 验证流程,下面逐条展开。打开 Remix,新建合约文件并粘贴上面的完整代码,选择^0.8.34版本编译部署即可复现。

第一步:部署后通过 getter 读取初始化值

部署合约后,Remix 的合约面板会自动列出CONSTANT_*IMMUTABLE_*两组变量的getter按钮。点击后即可看到初始化完成后的数值:constant变量显示声明时写入的字面量,immutable变量显示构造函数中写入的值(如当前合约地址、部署区块号与test()的返回值9)。

第二步:尝试修改 constant 变量

在合约中新增一个函数尝试给CONSTANT_NUM等变量重新赋值(例如CONSTANT_NUM = 777;),随后点击编译。Remix 会在编译面板中抛出一连串红色错误,核心信息为:

TypeError: Cannot assign to a constant variable.

这印证了教程的结论:constant变量初始化后不可赋值,任何修改尝试都会被编译器直接拒绝。

第三步:尝试重复初始化 immutable 变量

在构造函数中对一个已在声明处初始化过的immutable变量(如IMMUTABLE_NUM)再次赋值,编译时同样会报错:

TypeError: Immutable state variable already initialized.

注意该错误指向的是构造函数中重复赋值的那一行,说明 Solidity 精确地定位到了非法操作的位置。

总结

本讲围绕 Solidity 中两个"只读化"关键字展开:

  • constant(常量):必须在声明时初始化,之后永远不可修改,适用于编译期即可确定且永不变化的字面量;
  • immutable(不变量):可在声明时构造函数中初始化,更为灵活,适用于部署时刻才能确定、此后又不应改变的数据(合约地址、区块号等);
  • 类型约束:数值类型两者皆可;string/bytes只能用于constant
  • 收益:让不该变的变量保持不变,在提升合约安全性的同时节省gas

在编写合约时,凡是"确定性数据"都应当优先考虑用constantimmutable固化,这既是良好的编码习惯,也是合约安全与成本优化的基本功。若需复习状态变量的初始值规则,可继续阅读仓库中的 08_InitialValue/readme.md。

【免费下载链接】WTF-SolidityWTF Solidity 极简入门教程,供小白们使用。Now supports English! 官网: https://wtf.academy项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-Solidity

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 13:00:23

OpenCut 开源视频编辑器贡献指南:2 小时合入你的第一个 PR

OpenCut 开源视频编辑器贡献指南:2 小时合入你的第一个 PR 【免费下载链接】OpenCut The open-source CapCut alternative 项目地址: https://gitcode.com/GitHub_Trending/ap/OpenCut OpenCut 是一个免费的开源视频编辑器,定位是 CapCut 的开源替…

作者头像 李华
网站建设 2026/9/15 12:59:24

开放式运动耳机选购指南:从耳廓生物力学到声学安全

1. 为什么“开放式”不是运动耳机的万能解药?先破除三个认知误区“开放式运动耳机怎么选?”——这个问题背后藏着大量被营销话术裹挟的真实困惑。我从2018年开始系统测评运动音频设备,累计拆解过137款标称“开放式”的产品,覆盖跑…

作者头像 李华
网站建设 2026/9/15 12:56:43

批量下载抖音音频:douyin-downloader 上手指南

批量下载抖音音频:douyin-downloader 上手指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support. 抖音…

作者头像 李华