可见性和Getters(Visibility and Getters)
Solidity可以理解两种函数调用:
- “内部调用”,不创建一个真实的EVM调用,也称为“消息调用”
- “外部调用”,要创建一个真实的EVM调用,
有四种的函数和状态变量的可见性:
- 函数可以被定义为
external
,public
,internal
或private
,默认是public
。 - 状态变量不能为
external
,默认是internal
。
external
: 外部函数是合约接口的一部分,这意味着它们可以从其他合约调用, 也可以通过事务调用。外部函数f
不能被内部调用,即 f()
不执行,但this.f()
执行。外部函数在接收大数组时更有效。
public
:公共函数是合约接口的一部分,可以通过内部调用或消息调用。对公共状态变量而言,会自动生成getter
函数。
internal
:内部的函数和状态变量只能内部访问,即当前合约或由它派生的合约,不使用关键字this
。
private
:私有的函数和状态变量只能在所在的合约中可见, 在派生的合约中不可见。
注解 |
---|
合约内所有内容对于所有的外部观察者可见。用private 仅仅防止其他合约来访问和修改该合约中信息, 但它对blockchain之外的整个世界仍然可见。 |
可见性修饰符放在在状态变量的类型之后,或参数列表和函数返回的参数列表之间。
pragma solidity ^0.4.16;
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()
来检索状态存储中的数据值,但不能调用f
.。合约E
是从C
派生的,因此可以调用compute
。
// 这段代码无法编译
pragma solidity ^0.4.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); // error: member `f` is not visible
c.setData(3);
local = c.getData();
local = c.compute(3, 5); // error: member `compute` is not visible
}
}
contract E is C {
function g() public {
C c = new C();
uint val = compute(3, 5); // access to internal member (from derived to parent contract)
}
}
Getter函数(Getter Functions)
编译器会自动为所有public状态变量创建getter函数。对于下面的合约,编译器将生成一个名为data
的函数,该函数不接受任何参数,并返回uint
,即状态变量data
的值。状态变量的初始化可以在声明中完成。
pragma solidity ^0.4.0;
contract C {
uint public data = 42;
}
contract Caller {
C c = new C();
function f() public {
uint local = c.data();
}
}
getter函数具有外部可见性。
- 如果在内部访问符号(即不使用
this.
关键字),则将其作为状态变量。 - 如果它是外部访问的(即使用
this.
),则将其作为函数。
下一个例子更复杂:
pragma solidity ^0.4.0;
contract Complex {
struct Data {
uint a;
bytes3 b;
mapping (uint => uint) map;
}
mapping (uint => mapping(bool => Data[])) public data;
}
这会生成一个如下形式的函数:
function data(uint arg1, bool arg2, uint arg3) public returns (uint a, bytes3 b) {
a = data[arg1][arg2][arg3].a;
b = data[arg1][arg2][arg3].b;
}
注意:struct中的mapping被省略,因为没有好的方法来提供mapping的key。