# 函數(Function Types)
函數類型即是函數這種特殊的類型。
- 可以將一個函數賦值給一個變量,一個函數類型的變量。
- 還可以將一個函數作為參數進行傳遞。
- 也可以在函數調用中返回一個函數。
函數類型有兩類;可分為`internal`和`external`函數。
## 內部函數(internal)
因為不能在當前合約的上下文環境以外的地方執行,內部函數只能在當前合約內被使用。如在當前的代碼塊內,包括內部庫函數,和繼承的函數中。
## 外部函數(External)
外部函數由地址和函數方法簽名兩部分組成。可作為`外部函數調用`的參數,或者由`外部函數調用`返回。
## 函數的定義
完整的函數的定義如下:
```
function (<parameter types>) {internal(默認)|external} [constant] [payable] [returns (<return types>)]
```
若不寫類型,默認的函數類型是`internal`的。如果函數沒有返回結果,則必須省略`returns`關鍵字。下面我們通過一個例子來了解一下。
```
pragma solidity ^0.4.0;
contract Test{
//默認是internal類型的
function noParameter() returns (uint){}
//無返回結果
function noReturn1(uint x) {}
//如果無返回結果,必須省略`returns`關鍵字
//function noReturn2(uint x) returns {}
}
```
如果一個函數變量沒有初始化,直接調用它將會產生異常。如果`delete`了一個函數后調用,也會發生同樣的異常。
如果`外部函數`類型在`Solidity`的上下文環境以外的地方使用,他們會被視為`function`類型。編碼為20字節的函數所在地址,緊跟4字節的函數方法簽名的共占24字節的`bytes24`類型。
合約中的`public`的函數,可以使用`internal`和`external`兩種方式來調用。下面來看看,兩種方式的不同之處。
## 函數的`internal`與`external`:
調用一個函數`f()`時,我們可以直接調用`f()`,或者使用`this.f()`。但兩者有一個區別。前者是通過`internal`的方式在調用,而后者是通過`external`的方式在調用。請注意,這里關于`this`的使用與大多數語言相背。下面通過一個例子來了解他們的不同:
```
pragma solidity ^0.4.5;
contract FuntionTest{
function internalFunc() internal{}
function externalFunc() external{}
function callFunc(){
//直接使用內部的方式調用
internalFunc();
//不能在內部調用一個外部函數,會報編譯錯誤。
//Error: Undeclared identifier.
//externalFunc();
//不能通過`external`的方式調用一個`internal`
//Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
//this.internalFunc();
//使用`this`以`external`的方式調用一個外部函數
this.externalFunc();
}
}
contract FunctionTest1{
function externalCall(FuntionTest ft){
//調用另一個合約的外部函數
ft.externalFunc();
//不能調用另一個合約的內部函數
//Error: Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
//ft.internalFunc();
}
}
```
## 函數例子(官方)
```
pragma solidity ^0.4.0;
library ArrayUtils{
function range(uint length) internal returns (uint[] memory r){
r = new uint[](length);
for(uint i = 0; i < length; i++){
r[i] = i;
}
}
function map(uint[] memory self,
function(uint) returns (uint) f
)
internal
returns (uint[] memory r)
{
r = new uint[](self.length);
for(uint i = 0; i < self.length; i++){
r[i] = f(self[i]);
}
}
function reduce(uint[] memory self,
function(uint x, uint y) returns(uint) f
)
internal
returns (uint r)
{
r = self[0];
for(uint i = 1; i < self.length; i++){
r = f(r, self[i]);
}
}
}
contract Pyramid{
using ArrayUtils for *;
function pryamid(uint length) returns (uint){
return ArrayUtils.range(length).map(square).reduce(sum);
}
function square(uint x) returns (uint){
return x * x;
}
function sum(uint x, uint y) returns (uint){
return x + y;
}
}
```
Question?
- `library`是什么呢。
- `library`引入時為什么使用`using`,這和文件引入的`import`有何區別。
- `library`內的函數全是`internal`的。
- `library`內的函數,他的參數函數為什么是`internal`的,不應該是`external`的?
- `uint[]`是什么類型,不能寫做`[]uint`
- `memory`又是什么呢,為什么`map`函數明明是兩個參數,但只需要傳一個呢。
- Solidity語言
- 入門說明
- Solidity智能合約文件結構
- 智能合約源文件的基本要素概覽
- 值類型
- 類型
- 布爾
- 整型
- 地址
- 字節數組
- 小數
- 字符串
- 十六進制字面量
- 枚舉
- 函數
- 引用類型
- 引用類型
- 數據位置
- 數組
- 數據結構
- 雜項
- 映射
- 左值運算符
- 類型間的轉換
- 類型推斷
- 單位
- 貨幣單位
- 時間單位
- 語言內置特性
- 特殊變量及函數
- 數學和加密函數
- 地址相關
- 進階
- 入參和出參
- 控制結構
- 函數調用
- 創建合約實例
- 表達式的執行順序
- 賦值
- 作用范圍和聲明
- 異常
- 內聯匯編
- 合約詳解
- 合約
- 可見性或權限控制
- 訪問函數
- 函數修改器
- 常狀態變量
- 回退函數
- 事件
- 繼承
- 接口
- 其它
- 庫
- 狀態變量的存儲模型
- 內存變量的存局
- 調用數據的布局