まず、このセクションの完全なコードを示します。
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(interface{})
}
このインターフェイスは Call() メソッドを実装する必要があります。呼び出し時には、interface{} 型の変数が渡されます。この型の変数は任意の型の値を表します。
次に、インターフェイスの実装に構造体を使用します。
構造体はインターフェースを実装します
Invoker インターフェイスを実装するための構造体のコードは次のとおりです。
// Structure Type
type Struct struct {
}
// Invokerの呼び出しを実装する
func (s *Struct) Call(p interface{}) {
fmt.Println("from struct", p)
}
コードの説明は次のとおりです。
- 2行目は構造体を定義していますが、この例の構造体はメンバを必要とせず、主にInvokerの実装方法を示しています。
- 6 行目の Call() は構造体のメソッドです。このメソッドの機能は、構造体の値と渡されたインターフェースの型を出力することです。{}
定義された Struct 型をインスタンス化し、それを呼び出し用のインターフェイスに渡します。コードは次のとおりです。
var invoker Invoker
s := new(Struct)
invoker = s
invoker.Call("こんにちは")
コードの説明は次のとおりです。
- 行 2 では、Invoker 型の変数を宣言しています。
- 5 行目、 new を使用して構造体をインスタンス化します。この行は s:=&Struct としても記述できます。
- 8 行目では、 の型は *Struct であり、Invoker インターフェイス型がすでに実装されているため、invoker への割り当ては成功しています。
- 11行目ではインターフェースのCall()メソッドを通じてhelloが渡されており、このときStruct構造体のCall()メソッドが呼び出されます。
次に、機能の実装構造の違いを比較します。
コード出力は次のとおりです。
from struct こんにちは
関数の本体はインターフェイスを実装します
関数の宣言でインターフェイスを直接実装することはできません。関数が型として定義された後、その型を使用して構造体が実装されます。型メソッドが呼び出されるときは、関数本体を呼び出す必要があります。
// Function is defined as a type
type FuncCaller func(interface{})
// Implementation of Invoker's Call
func (f FuncCaller) Call(p interface{}) {
// Call the body of the f() function
f(p)
}
コードの説明は次のとおりです。
- 2 行目では、func(interface{}) をタイプ FuncCaller として定義します。
- 5 行目では、FuncCaller の Call() メソッドが Invoker の Call() メソッドを実装します。
- 8行目では、func(interface{})に関係なくFuncCallerのCall()メソッドが呼び出されており、関数本体を手動で呼び出す必要があります。
上記のコードは関数の型のみを定義しており、関数自体によって論理的に処理する必要があります。FuncCaller をインスタンス化する必要はありません。関数を FuncCaller 型に変換するだけで済みます。関数のソースは名前付き関数にすることができます、匿名関数またはクロージャ。次のコードを参照してください。
// Declare interface variable
var invoker Invoker
// Convert anonymous function to FuncCaller type, and then assign it to the interface
invoker = FuncCaller(func(v interface{}) {
fmt.Println("from function", v)
})
// Use the interface to call FuncCaller.Call, which will invoke the underlying function
invoker.Call("hello")
コードの説明は次のとおりです。
- 2 行目ではインターフェース変数を宣言しています。
- 5 行目では、func(v Interface{}){} 匿名関数が FuncCaller 型に変換されます (関数のシグネチャのみ変換可能)。このとき、FuncCaller 型は Invoker の Call() メソッドを実装し、呼び出し側インターフェイスへの割り当ては成功しました。
- 10 行目、インターフェイス メソッド呼び出しを使用します。
コード出力は次のとおりです。
from function hello
HTTP パッケージにはハンドラー インターフェイスの定義が含まれており、コードは次のとおりです。
type handler interface {
ServeHTTP(ResponseWriter, *Request)
}
ハンドラーは、各 HTTP リクエストとレスポンスの処理を定義するために使用されます。
同時に、処理関数を使用してインターフェイスを実装することもできます。これは次のように定義されます。
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 は、次のように定義された HandleFunc() メソッドを持つ ServeMux 構造体です。
func (mux *ServeMux) HandleFunc(pattern string, handler func
(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}
上記のコードは、外部から渡された関数 handler() を HandlerFunc 型に変換します。HandlerFunc 型は、Handler の ServeHTTP メソッドを実装します。基になる層は、さまざまな型を使用して、処理用の Handler インターフェイスを実装できます。