在 Solidity 编程语言中,可视范围(Visibility)用于控制合约中变量和函数的访问权限。这对于确保合约的安全性、模块化以及代码的可维护性至关重要。Solidity 提供了四种可视范围修饰符:public
、private
、external
和 internal
。以下将结合给定代码进行详细介绍。
注意:使用继承时请确保代码的正确性,以防丢失个人财产,在这里友情提示您,不要复制来源不明的solidity代码并进行部署。本文为自己梳理总结,如有不足还请指出,感谢包容。
学习更多solidity知识请访问 Github -- solidity基础 ,更多实例在 Smart contract
-
public:外部和内部可见(为 storage/state 变量创建 getter 函数)
private:仅在当前合同中可见
external:仅在外部可见(仅适用于函数)- 即只能通过消息调用(通过this.func)
internal:仅在内部可见,合约内部进行调用
1. public
可视范围
- 定义:具有
public
可视范围的变量或函数在合约内部和外部都可见。对于状态变量(storage
变量),Solidity 会自动为其创建一个getter
函数,使得外部合约或用户可以通过该getter
函数访问该变量的值。 - 实例:在
VisibilityBase
合约中,uint public z = 2;
声明了一个public
状态变量z
。外部合约或用户可以通过调用getter
函数(例如contractInstance.z()
)来获取z
的值。同时,在合约内部,其他函数也可以直接访问z
。例如:
function accessZ() public view returns (uint) {
return z;
}
2. private
可视范围
- 定义:
private
可视范围的变量和函数仅在当前合约中可见。这意味着其他合约,包括继承自该合约的子合约,都无法访问这些private
成员。 - 实例:在
VisibilityBase
合约中,uint private x = 0;
声明了一个private
状态变量x
。只有在VisibilityBase
合约内部的函数才能访问x
。例如:
function accessX() private view returns (uint) {
return x;
}
外部合约无法直接访问 x
,继承自 VisibilityBase
的子合约也不能访问 x
。
3. external
可视范围
- 定义:
external
可视范围仅适用于函数,意味着该函数只能通过外部消息调用(例如通过this.func
的方式),而不能在合约内部直接调用。外部函数通常用于处理大量数据,因为它们可以接收calldata
,这是一种只读的、存储在合约调用栈中的数据类型,比memory
更节省 gas。 - 实例:在
VisibilityBase
合约中,function externalFunc() external pure returns (uint) { return 300; }
定义了一个external
函数externalFunc
。外部合约可以通过以下方式调用:
VisibilityBase contractInstance = new VisibilityBase();
uint result = contractInstance.externalFunc();
然而,在 VisibilityBase
合约内部,不能直接调用 externalFunc
,例如:
// 以下代码会报错
function internalCallExternal() public pure {
externalFunc(); // 错误:不能在内部直接调用 external 函数
}
4. internal
可视范围
- 定义:
internal
可视范围的变量和函数仅在合约内部以及继承自该合约的子合约中可见。在合约内部,函数可以直接调用internal
函数,而不需要通过合约实例。 - 实例:在
VisibilityBase
合约中,uint internal y = 1;
声明了一个internal
状态变量y
,function internalFunc() internal pure returns (uint) { return 100; }
定义了一个internal
函数internalFunc
。在VisibilityBase
合约内部,其他函数可以直接访问y
和调用internalFunc
,例如:
function accessYAndInternalFunc() public view returns (uint) {
return y + internalFunc();
}
如果有一个继承自 VisibilityBase
的子合约,子合约也可以访问 y
和调用 internalFunc
。例如:
contract SubContract is VisibilityBase {
function accessFromSub() public view returns (uint) {
return y + internalFunc();
}
}
总结
-
public
:状态变量和函数可以在合约内部和外部访问。对于状态变量,Solidity 会自动生成 getter 函数。 -
private
:状态变量和函数只能在当前合约内部访问,外部和其他合约无法访问。 -
internal
:状态变量和函数可以在当前合约内部以及继承它的子合约中访问,但不能在外部访问。 -
external
:函数只能在合约外部调用,不能在合约内部直接调用。
代码实例
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract VisibilityBase {
uint private x = 0;
uint internal y = 1;
uint public z = 2;
function privateFunc () private pure returns (uint) {
return 0;
}
function internalFunc() internal pure returns (uint) {
return 100;
}
function publicFunc() public pure returns (uint) {
return 200;
}
function externalFunc() external pure returns (uint) {
return 300;
}
}
在这个合约中:
-
x
是private
,只能在VisibilityBase
内部访问。 -
y
是internal
,可以在VisibilityBase
及其子合约中访问。 -
z
是public
,可以在合约内部和外部访问。 -
privateFunc
是private
,只能在VisibilityBase
内部调用。 -
internalFunc
是internal
,可以在VisibilityBase
及其子合约中调用。 -
publicFunc
是public
,可以在合约内部和外部调用。 -
externalFunc
是external
,只能在合约外部调用。