Solidity 继承覆盖 public 常量
Solidity inheritance override public constant
简单代码:
pragma solidity 0.8.4;
contract A {
uint256 public constant X = 1;
}
contract B is A {
uint256 override public constant X = 2;
}
不幸的是编译错误:
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;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
有什么方法可以覆盖 public 常量吗?
常量变量的值在编译过程中赋值,然后存储在内存中。很遗憾,您无法更改它。
我不知道你的代码中 X
的用途,但是可以轻松地重新分配简单的状态变量,并且通过使用 onlyOwner 修饰符,你将拥有对该函数的独占访问权,因此你可以更改变量随时。
function changeValue(uint256 newValue) public onlyOwner {
X = newValue;
}
简短回答:不可以。您只能覆盖 Solidity 中的函数。
长答案:
有趣的是,由于编译器为public个状态变量(包括常量)生成getter个函数,你实际上可以用它们来覆盖函数(Contracts > Inheritance > Function Overriding):
Public state variables can override external functions if the parameter and return types of the function matches the getter function of the variable
While public state variables can override external functions, they themselves cannot be overridden.
因此,如果 X
是一个函数,这将完全没问题:
contract A {
function X() external virtual returns (uint256) {
return 1;
}
}
contract B is A {
uint256 public constant override X = 2;
}
你不能反过来做,原因是这可能需要删除已经为状态变量保留的槽。基础合约可能包含通过变量访问该插槽的代码,因此编译器允许这样做是不安全的。
但是这个推理不适用于常量——它们不占用任何存储空间。用变量覆盖变量或用常量覆盖常量也不是问题。这似乎是一个纯粹的语法限制,所以如果你有一个强大的用例,你可以尝试提交一个 feature request。问题是——如果你想改变它的值,它真的是一个常数吗,即使它只有一次?我认为在大多数语言中这是行不通的。您也许可以用一个新的常量来遮蔽常量,但不能真正覆盖这个词的完整含义——也就是说,从基 class 调用的函数会看到更改后的值。
您的用例可能更适合 immutable
,这是一种“运行时常量”。与编译时常量不同,它不受编译器可以对常量执行的所有相同优化的约束,并且不能在需要真正常量的上下文中使用(例如,您不能使用它来定义静态数组的长度)但它无法在运行时更改并且不占用任何存储空间,因此它可能仍然符合您的要求。它只能在构造时分配一次,然后将结果硬编码到构造函数生成的字节码中。
contract A {
uint256 public immutable X;
constructor(uint256 _x) {
X = _x;
}
}
contract B is A(2) {}
简单代码:
pragma solidity 0.8.4;
contract A {
uint256 public constant X = 1;
}
contract B is A {
uint256 override public constant X = 2;
}
不幸的是编译错误:
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;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
有什么方法可以覆盖 public 常量吗?
常量变量的值在编译过程中赋值,然后存储在内存中。很遗憾,您无法更改它。
我不知道你的代码中 X
的用途,但是可以轻松地重新分配简单的状态变量,并且通过使用 onlyOwner 修饰符,你将拥有对该函数的独占访问权,因此你可以更改变量随时。
function changeValue(uint256 newValue) public onlyOwner {
X = newValue;
}
简短回答:不可以。您只能覆盖 Solidity 中的函数。
长答案:
有趣的是,由于编译器为public个状态变量(包括常量)生成getter个函数,你实际上可以用它们来覆盖函数(Contracts > Inheritance > Function Overriding):
Public state variables can override external functions if the parameter and return types of the function matches the getter function of the variable
While public state variables can override external functions, they themselves cannot be overridden.
因此,如果 X
是一个函数,这将完全没问题:
contract A {
function X() external virtual returns (uint256) {
return 1;
}
}
contract B is A {
uint256 public constant override X = 2;
}
你不能反过来做,原因是这可能需要删除已经为状态变量保留的槽。基础合约可能包含通过变量访问该插槽的代码,因此编译器允许这样做是不安全的。
但是这个推理不适用于常量——它们不占用任何存储空间。用变量覆盖变量或用常量覆盖常量也不是问题。这似乎是一个纯粹的语法限制,所以如果你有一个强大的用例,你可以尝试提交一个 feature request。问题是——如果你想改变它的值,它真的是一个常数吗,即使它只有一次?我认为在大多数语言中这是行不通的。您也许可以用一个新的常量来遮蔽常量,但不能真正覆盖这个词的完整含义——也就是说,从基 class 调用的函数会看到更改后的值。
您的用例可能更适合 immutable
,这是一种“运行时常量”。与编译时常量不同,它不受编译器可以对常量执行的所有相同优化的约束,并且不能在需要真正常量的上下文中使用(例如,您不能使用它来定义静态数组的长度)但它无法在运行时更改并且不占用任何存储空间,因此它可能仍然符合您的要求。它只能在构造时分配一次,然后将结果硬编码到构造函数生成的字节码中。
contract A {
uint256 public immutable X;
constructor(uint256 _x) {
X = _x;
}
}
contract B is A(2) {}