Solidity 继承覆盖公共常量

Hel*_*eda 4 inheritance solidity

简单代码:

pragma solidity 0.8.4;

contract A {
    uint256 public constant X = 1;
}

contract B is A {
    uint256 override public constant X = 2;
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,编译时出现错误:

TypeError: Cannot override public state variable.
 --> contracts/mocks/StakePoolMock.sol:4:5:
  |
4 |     uint256 public constant X = 1;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Note: Overriding public state variable is here:
 --> contracts/mocks/StakePoolMock.sol:8:5:
  |
8 |     uint256 override public constant X = 2;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

有什么办法可以覆盖公共常量吗?

cam*_*eel 6

简短的回答:不可以。您只能覆盖 Solidity 中的函数。


长答案

有趣的是,由于编译器为公共状态变量(包括常量)生成 getter 函数,因此您实际上可以使用它们来重写函数(Contracts > Inheritance > Function Overriding):

如果函数的参数和返回类型与变量的 getter 函数匹配,则公共状态变量可以覆盖外部函数

虽然公共状态变量可以覆盖外部函数,但它们本身不能被覆盖。

所以如果X是一个函数,那就完全没问题了:

contract A {
    function X() external virtual returns (uint256) {
        return 1;
    }
}

contract B is A {
    uint256 public constant override X = 2;
}
Run Code Online (Sandbox Code Playgroud)

但您不能以相反的方式执行此操作,原因是这可能需要删除已为状态变量保留的槽。基础合约可能包含通过变量访问该槽的代码,因此编译器允许这样做是不安全的。

然而,这种推理不适用于常量——它们不占用任何存储空间。当用变量覆盖变量或用常量覆盖常量时,这也不是问题。这似乎是纯粹的语法限制,因此如果您有很强的用例,您可以尝试提交功能请求。问题是 - 如果你想改变它的值,即使它只有一次,它真的是一个常量吗?我认为在大多数语言中这是行不通的。您也许可以用一个新的常量来隐藏该常量,但不能真正覆盖该词的完整含义 - 即,从基类调用的函数将看到更改后的值。

您的用例可能更适合使用immutable,它是一种“运行时常量”。与编译时常量不同,它不受编译器可以对常量执行的所有相同优化的影响,并且不能在需要真正常量的上下文中使用(例如,您不能使用它来定义静态数组的长度),但它无法在运行时更改,并且不占用任何存储空间,因此它仍然可以满足您的要求。它只能在构造时分配一次,然后将结果硬编码在构造函数生成的字节码中。

contract A {
    uint256 public immutable X;

    constructor(uint256 _x) {
        X = _x;
    }
}

contract B is A(2) {}
Run Code Online (Sandbox Code Playgroud)