侧边栏壁纸
博主头像
秋码记录

一个游离于山间之上的Java爱好者 | A Java lover living in the mountains

  • 累计撰写 29 篇文章
  • 累计创建 40 个标签
  • 累计创建 185 个分类

玩以太坊链上项目的必备技能(Constant 和 Immutable 状态变量-Solidity之旅十六)

编译器生成的合约创建代码将在返回合约之前修改合约的运行时代码,方法是将对不可变量的所有引用替换为分配给它们的值。 如果要将编译器生成的运行时代码与实际存储在区块链中的代码进行比较,则这一点很重要。

constant(常量)

说到常量这一概念,拥有现代编程经历的您,对这一词再熟悉不过了。

常量常量,顾名思义便是变量值始终不变,这在很多面向对象程序语言中都有。

相对 Solidity 来说,它也是支持常量的。

假若将状态变量(State Vriable)声明为constant(常量),而它的值是在编译时有确定的表达式来给它赋值。

我们知道常量值是在编译时确定的,所以区块数据(例如 block.timestamp, address(this).balance 或者 block.number)或执行数据( msg.valuegasleft() )或对外部合约的调用来给它们赋值都是不允许的。

允许可能对内存分配产生副作用(side-effect)的表达式,但那些可能对其他内存对象产生副作用的表达式则不允许。

内建(built-in)函数 keccak256sha256ripemd160ecrecoveraddmodmulmod 是允许的(即使他们确实会调用外部合约, 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;

}

img

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;
    }

}

img

// 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;
    }

}

img