Solidity的函数类型以及可见性分析(类比Java)
条评论函数类型
函数也是一种类型(值类型),它是函数的调用方式。函数类型可以被赋值吗,作为参数和返回结果。函数可以分为两类:内部函数(Internal)和外部函数(External)。
内部函数Internal(默认): 只能在当前合约内被调用(在当前的代码块内,包括内部库函数,和继承的函数中)。
外部函数External: 由地址和函数方法签名两部分组成,可作为外部函数调用的参数,或返回值。
1 | function (<parameter types>) {internal|external} [pure|constant|view|payable] [returns (<return types>)] |
external调用时,实际是向目标合约发送一个消息调用。消息中的函数定义部分是24字节大小的消息体。其中20字节为地址,4字节为函数签名。
有两个方式访问函数,一种是直接用函数名a(), 一种是this.a(), 前者用于内部函数,后者用于外部函数。
1 | pragma solidity ^0.4.0; |
函数可见性分析
函数的可见性,表明了函数的可以被访问的级别。
- public(默认)
public的函数既允许以internal的方式调用,也允许external的方式调用。
public函数由于被外部合约访问,是合约对外接口的一部分。 - private
只能在当前函数中被调用。这禁止了其它合约的访问和修改数据。 - internal
只能在当前的合约或者继承的子孙合约中,只允许以internal的方式调用。 - external
仅能够被外部合约调用。在内部合约访问时,也只能用外部访问方式访问。
1 | pragma solidity ^0.4.0; |
运行代码。观察分析耗费的gas值。

1 | transact to Test.a pending ... |
a()和b()比较,可以发现:public函数开销更大。
为什么?
当使用public 函数时,Solidity会立即复制数组参数数据到内存, 而external函数则是从calldata读取,而分配内存开销比直接从calldata读取要大的多。
那为什么public函数要复制数组参数数据到内存呢?是因为public函数可能会被内部调用,而内部调用数组的参数是当做指向一块内存的指针。
对于external函数不允许内部调用,它直接从calldata读取数据,省去了复制的过程。
所以,如果确认一个函数仅仅在外部访问,请用external。
c()和d()比较,可以发现:d()的开销要大。
它采用了this.b()的方法去调用当前合约的内部函数,会有一个大开销的CALL调用,并且它传参的方式也比内部传递开销更大。
因此,当需要内部调用的时候,请用public。
类比Java
- Java:
| 作用域 | 当前类 | 同一package | 子孙类 | 其他package |
|---|---|---|---|---|
| public | √ | √ | √ | √ |
| protected | √ | √ | √ | x |
| default | √ | √ | x | x |
| private | √ | x | x | x |
- Solidity:
| 作用域 | 当前合约 | 子孙合约 | 外部合约 |
|---|---|---|---|
| public | √ | √ | √ |
| private | √ | x | x |
| internal | √ | √ | x |
| external | x (可以this方式访问) | x | √ |
参考文档
文章作者:米兰
原始链接:https://blog.milanchen.site/posts/solidity-function-visibility.html
版权声明:转载请声明出处