编译器生成的合约创建代码将在返回合约之前修改合约的运行时代码,方法是将对不可变量的所有引用替换为分配给它们的值。 如果要将编译器生成的运行时代码与实际存储在区块链中的代码进行比较,则这一点很重要。
constant(常量)
说到常量
这一概念,拥有现代编程经历的您,对这一词再熟悉不过了。
常量
,常量
,顾名思义便是变量值始终不变,这在很多面向对象程序语言中都有。
相对 Solidity 来说,它也是支持常量
的。
假若将状态变量(State Vriable)
声明为constant(常量)
,而它的值是在编译时
有确定的表达式来给它赋值。
我们知道常量
值是在编译时
确定的,所以区块数据
(例如 block.timestamp
, address(this).balance
或者 block.number
)或执行数据( msg.value
或 gasleft()
)或对外部合约的调用来给它们赋值都是不允许的。
允许可能对内存分配产生副作用(side-effect)的表达式,但那些可能对其他内存对象产生副作用的表达式则不允许。
内建(built-in)函数 keccak256
, sha256
, ripemd160
, ecrecover
, addmod
和 mulmod
是允许的(即使他们确实会调用外部合约, keccak256
除外)。
允许内存分配器的副作用的原因是它可以构造复杂的对象,例如: 查找表(lookup-table)。 此功能尚不完全可用。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract ConstantExample {
address public constant MY_ADDRESS = 0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc;
uint public constant MY_UINT = 123;
}
immutable(不可变量)
将状态变量
声明为immutable(不可变量)
较constant
声明的状态变量
限制少。
可以在合约的构造函数中或声明时为不可变的变量分配任意值。 不可变量只能赋值一次,并且在赋值之后才可以读取。
编译器生成的合约创建代码将在返回合约之前修改合约的运行时代码,方法是将对不可变量的所有引用替换为分配给它们的值。 如果要将编译器生成的运行时代码与实际存储在区块链中的代码进行比较,则这一点很重要。
不可变量可以在声明时赋值,不过只有在合约的构造函数执行时才被视为视为初始化。 这意味着,你不能用一个依赖于不可变量的值在行内初始化另一个不可变量。 不过,你可以在合约的构造函数中这样做。
这是为了防止对状态变量初始化和构造函数顺序的不同解释,特别是继承时,出现问题。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract ImmutableExample {
address public immutable MY_ADDRESS;
uint public immutable MY_UINT;
constructor(uint _myUint) {
MY_ADDRESS = msg.sender;
MY_UINT = _myUint;
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract ConstantImmutableExample {
string constant TEXT = "abc";
bytes32 constant MY_HASH = keccak256("abc");
uint immutable decimals;
uint immutable maxBalance;
address immutable owner = msg.sender;
constructor(uint decimals_, address ref) {
decimals = decimals_;
maxBalance = ref.balance;
}
function isBalanceTooHigh(address _other) public view returns (bool) {
return _other.balance > maxBalance;
}
}