合约(contract
)和其他语言的类(class
)很类似,合约添加的变量与函数,也是使用public
private
等关键字来控制变量和函数是否可以被外部使用。
如Counter
合约的如下定义:
uint public counter;
使用了 public
关键字, 表示 counter 是可以被公开访问的。
除 public
之外,还有几个关键字,来修饰属性与函数的可见性。
Solidity对函数和状态变量提供了4种可见性:external
、public
、internal
、private
。
1.状态变量可见性
状态变量有 3 种可见性:
public:
对于 public 状态变量会自动生成一个gitter 函数。 以便其他的合约读取他们的值。 当在用一个合约里使用是,外部方式访问 (如: this.x
) 会调用getter 函数,而内部方式访问 (如: x
) 会直接从存储中获取值。 Setter函数则不会被生成,所以其他合约不能直接修改其值。
internal:
内部可见性状态变量只能在它们所定义的合约和派生合同中访问。 它们不能被外部访问。 这是状态变量的默认可见性。
private:
私有状态变量就像内部变量一样,但它们在派生合约中是不可见的。
2.函数可见性
由于 Solidity 有两种函数调用:外部调用则会产生一个 EVM 调用,而内部调用不会, 更进一步, 函数可以确定器被内部及派生合约的可访问性,这里有 4 种可见性:
external:
外部可见性函数作为合约接口的一部分,意味着我们可以从其他合约和交易中调用。 一个外部函数 f
不能从内部调用(即 f
不起作用,但 this.f()
可以)。
public:
public 函数是合约接口的一部分,可以在内部或通过消息调用。
internal:
内部可见性函数访问可以在当前合约或派生的合约访问,不可以外部访问。 由于它们没有通过合约的ABI向外部公开,它们可以接受内部可见性类型的参数:比如映射或存储引用。
private:
private 函数和状态变量仅在当前定义它们的合约中使用,并且不能被派生合约使用。
可见性标识符的定义位置,对于状态变量来说是在类型后面,对于函数是在参数列表和返回关键字中间。
pragma solidity >=0.6.0 <0.9.0;
contract C {
function f(uint a) private pure returns (uint b) {
return a + 1;
}
function setData(uint a) internal {
data = a;
}
uint public data;
}
在下面的例子中,D
可以调用 c.getData()
来获取状态存储中 data
的值,但不能调用 f
。 合约 E
继承自 C
,因此可以调用 compute
。
pragma solidity >=0.4.16 <0.9.0;
contract C {
uint private data;
function f(uint a) private returns(uint b) {
return a + 1;
}
function setData(uint a) public {
data = a;
}
function getData() public returns(uint) {
return data;
}
function compute(uint a, uint b) internal returns (uint) {
return a+b;
}
}
// 下面代码编译错误
contract D {
function readData() public {
C c = new C();
uint local = c.f(7); // 错误:成员 `f` 不可见,private
c.setData(3);
local = c.getData();
local = c.compute(3, 5); // 错误:成员 `compute` 不可见
}
}
contract E is C {
function g() public {
C c = new C();
uint val = compute(3, 5); // 访问内部成员(从继承合约访问父合约成员)
}
}