函數和其他類型一樣都屬于“一等公民”,其他類型能夠實現接口,函數也可以,本節將對結構體與函數實現接口的過程進行對比。
首先給出本節完整的代碼:
~~~
package main
import (
"fmt"
)
// 調用器接口
type Invoker interface {
// 需要實現一個Call方法
Call(interface{})
}
// 結構體類型
type Struct struct {
}
// 實現Invoker的Call
func (s *Struct) Call(p interface{}) {
fmt.Println("from struct", p)
}
// 函數定義為類型
type FuncCaller func(interface{})
// 實現Invoker的Call
func (f FuncCaller) Call(p interface{}) {
// 調用f函數本體
f(p)
}
func main() {
// 聲明接口變量
var invoker Invoker
// 實例化結構體
s := new(Struct)
// 將實例化的結構體賦值到接口
invoker = s
// 使用接口調用實例化結構體的方法Struct.Call
invoker.Call("hello")
// 將匿名函數轉為FuncCaller類型,再賦值給接口
invoker = FuncCaller(func(v interface{}) {
fmt.Println("from function", v)
})
// 使用接口調用FuncCaller.Call,內部會調用函數本體
invoker.Call("hello")
}
~~~
有如下一個接口:
~~~
// 調用器接口
type Invoker interface {
// 需要實現一個Call()方法
Call(interface{})
}
~~~
這個接口需要實現 Call() 方法,調用時會傳入一個 interface{} 類型的變量,這種類型的變量表示任意類型的值。
接下來,使用結構體進行接口實現。
## 結構體實現接口
結構體實現 Invoker 接口的代碼如下:
~~~
// 結構體類型
type Struct struct {
}
// 實現Invoker的Call
func (s *Struct) Call(p interface{}) {
fmt.Println("from struct", p)
}
~~~
代碼說明如下:
* 第 2 行,定義結構體,該例子中的結構體無須任何成員,主要展示實現 Invoker 的方法。
* 第 6 行,Call() 為結構體的方法,該方法的功能是打印 from struct 和傳入的 interface{} 類型的值。
將定義的 Struct 類型實例化,并傳入接口中進行調用,代碼如下:
~~~
// 聲明接口變量
var invoker Invoker
// 實例化結構體
s := new(Struct)
// 將實例化的結構體賦值到接口
invoker = s
// 使用接口調用實例化結構體的方法Struct.Call
invoker.Call("hello")
~~~
代碼說明如下:
* 第 2 行,聲明 Invoker 類型的變量。
* 第 5 行,使用 new 將結構體實例化,此行也可以寫為 s:=&Struct。
* 第 8 行,s 類型為 \*Struct,已經實現了 Invoker 接口類型,因此賦值給 invoker 時是成功的。
* 第 11 行,通過接口的 Call() 方法,傳入 hello,此時將調用 Struct 結構體的 Call() 方法。
接下來,對比下函數實現結構體的差異。
代碼輸出如下:
~~~
from struct hello
~~~
## 函數體實現接口
函數的聲明不能直接實現接口,需要將函數定義為類型后,使用類型實現結構體,當類型方法被調用時,還需要調用函數本體。
~~~
// 函數定義為類型
type FuncCaller func(interface{})
// 實現Invoker的Call
func (f FuncCaller) Call(p interface{}) {
// 調用f()函數本體
f(p)
}
~~~
代碼說明如下:
* 第 2 行,將 func(interface{}) 定義為 FuncCaller 類型。
* 第 5 行,FuncCaller 的 Call() 方法將實現 Invoker 的 Call() 方法。
* 第 8 行,FuncCaller 的 Call() 方法被調用與 func(interface{}) 無關,還需要手動調用函數本體。
上面代碼只是定義了函數類型,需要函數本身進行邏輯處理,FuncCaller 無須被實例化,只需要將函數轉換為 FuncCaller 類型即可,函數來源可以是命名函數、匿名函數或閉包,參見下面代碼:
~~~
// 聲明接口變量
var invoker Invoker
// 將匿名函數轉為FuncCaller類型, 再賦值給接口
invoker = FuncCaller(func(v interface{}) {
fmt.Println("from function", v)
})
// 使用接口調用FuncCaller.Call, 內部會調用函數本體
invoker.Call("hello")
~~~
代碼說明如下:
* 第 2 行,聲明接口變量。
* 第 5 行,將 func(v interface{}){} 匿名函數轉換為 FuncCaller 類型(函數簽名才能轉換),此時 FuncCaller 類型實現了 Invoker 的 Call() 方法,賦值給 invoker 接口是成功的。
* 第 10 行,使用接口方法調用。
代碼輸出如下:
~~~
from function hello
~~~
## HTTP包中的例子
HTTP 包中包含有 Handler 接口定義,代碼如下:
~~~
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
~~~
Handler 用于定義每個 HTTP 的請求和響應的處理過程。
同時,也可以使用處理函數實現接口,定義如下:
~~~
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
~~~
要使用閉包實現默認的 HTTP 請求處理,可以使用 http.HandleFunc() 函數,函數定義如下:
~~~
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
~~~
而 DefaultServeMux 是 ServeMux 結構,擁有 HandleFunc() 方法,定義如下:
~~~
func (mux *ServeMux) HandleFunc(pattern string, handler func
(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}
~~~
上面代碼將外部傳入的函數 handler() 轉為 HandlerFunc 類型,HandlerFunc 類型實現了 Handler 的 ServeHTTP 方法,底層可以同時使用各種類型來實現 Handler 接口進行處理。
- 1.Go語言前景
- 2.Go語言環境搭建
- 3.Go語言的基本語法
- 3.1變量
- 3.1.1變量聲明
- 3.1.2變量初始化
- 3.1.3多個變量同時賦值
- 3.1.4匿名變量
- 3.1.5變量的作用域
- 3.1.6整型
- 3.1.7浮點類型
- 3.1.8復數
- 3.1.9bool類型
- 3.1.10字符串
- 3.1.11字符類型
- 3.1.12類型轉換
- 3.2常量
- 3.1.1const關鍵字
- 3.2.2模擬枚舉
- 4.Go語言的流程控制
- 4.2循環結構
- 4.3鍵值循環
- 4.4switch語句
- 4.5goto語句
- 4.6break語句
- 4.7continue語句
- 5.Go語言的函數
- 5.1函數聲明
- 5.2函數變量
- 5.3函數類型實現接口
- 5.4閉包
- 5.5可變參數
- 5.6defer(延遲執行語句)
- 5.7處理運行時錯誤
- 5.8宕機(panic)
- 5.9宕機恢復(recover)
- 5.10Test功能測試函數
- 6.Go語言的內置容器
- 6.1數組
- 6.2切片
- 6.3map
- 6.4sync.Map
- 6.5list
- 6.6range
- 7.Go語言的結構體
- 8.Go語言的接口
- 9.Go語言的常用內置包
- 10.Go語言的并發
- 11.Go語言的文件I/O操作
- 12.Go語言的網絡編程
- 13.Go語言的反射
- 14.Go語言的數據庫編程
- 15.Go語言密碼學算法
- 16.Go語言的gin框架
- 17.Go語言的網絡爬蟲
- 18.Go語言的編譯和工具鏈