Go 言語では実現関係が暗黙的に表現されます。 2 つの型間の実装関係は、コード内で明示的に表す必要はありません。 Go言語にはimplementsのようなキーワードはありません。 Go コンパイラーは、必要に応じて 2 つの型間の実装関係を自動的にチェックします。
インターフェイスを定義した後、呼び出し元がインターフェイスを正しくコンパイルして使用できるように、インターフェイスを実装する必要があります。インターフェイスを使用可能にするために、インターフェイスの実装は 2 つのルールに従う必要があります。
実装するインターフェースの条件1:インターフェースのメソッドが、インターフェースを実装する型のメソッドの形式と一致していること
このメソッドは、インターフェイスのシグネチャと型を一致させるメソッドを追加することで実装されます。署名には、メソッド内の名前、パラメータ リスト、および戻りパラメータ リストが含まれます。つまり、インターフェース型のメソッドの名前、パラメータリスト、戻りパラメータリストのいずれかの項目が、インターフェースによって実装されるメソッドと矛盾している限り、インターフェースのメソッドは実装されません。
データ書き込みのプロセスを抽象化するために、データ書き込みのために実装する必要があるメソッドを記述するために DataWriter インターフェイスが定義されています。インターフェイス内の WriteData() メソッドはデータを書き込むことを意味し、書き込み側はデータの書き込み場所を気にする必要はありません。それは書かれている。インターフェイスを実装する型が WriteData メソッドを実装する場合、データがどのような構造に書き込まれるかを具体的に書き込みます。ここでは、ファイル構造を使用して DataWriter インターフェイスの WriteData メソッドを実装しています。メソッド内では、データが書き込まれたことを示すログのみが出力されます。詳細な実装プロセスについては、次のコードを参照してください。
データライターの抽象化:
package main
import (
"fmt"
)
//データライタを定義する
type DataWriter interface {
WriteData(data interface{}) error
}
//ファイル構造を定義し、DataWriterを実装するために使用する
type file struct {
}
//WriteDataメソッドを実装するデータライタのインタフェース
func (d *file) WriteData(data interface{}) error {
//データの書き込みをシミュレートする
fmt.Println("WriteData:", data)
return nil
}
func main() {
//fileのインスタンス化
f := new(file)
//DataWriterのインターフェイスを宣言する
var writer DataWriter
//writerに* file型が割り当てられる
writer = f
//DataWriterインターフェースを使用してデータを書き込みます
writer.WriteData("data")
}
コードの説明は次のとおりです。
- 8 行目は DataWriter インターフェイスを定義します。このインターフェースには、WriteData() というメソッドが 1 つだけあります。このメソッドは、interface{} 型のデータを入力し、考えられるエラーを示すエラー構造体を返します。
- 17 行目で、file の WriteData() メソッドはポインタ レシーバを使用します。 Interface{} 型のデータを入力すると、エラーが返されます。
- 27 行目では、インスタンス化されたファイルが f に割り当てられ、f のタイプは *file です。
- 30行目ではDataWriter型のライターインタフェース変数を宣言しています。
- 33 行目では、*file 型の f を DataWriter インターフェイスのライターに割り当てますが、2 つの変数の型は一致しません。しかし、writer はインターフェイスであり、f は DataWriter() のすべてのメソッドを完全に実装しているため、代入は成功します。
- 36 行目では、DataWriter インターフェイス タイプの作成者が WriteData() メソッドを使用して文字列を書き込みます。
コードを実行すると、出力は次のようになります。
WriteData: data
型がインターフェイスを実装できない場合、コンパイラはエラーを報告します。インターフェイスが実装できない一般的なエラーをいくつか次に示します。
1) 関数名の不一致によるエラー
上記のコードに基づいて、コンパイル エラーを引き起こすコードの一部を変更してみて、コンパイラのエラー レポートを通じてインターフェイスの実装方法を理解します。まず、ファイル構造の WriteData() メソッド名を変更し、メソッド シグネチャ (17 行目) を次のように変更します。
func(d *file)WriteDataX(data interface {})error{
コードをコンパイルしてエラーを報告します。
cannot use f (type *file) as type DataWriter in assignment:
*file does not implement DataWriter (missing WriteData method)
エラーの場所は 33 行目です。エラーの意味は、f 変数 (タイプ *file) を DataWriter として割り当てることができないことです。原因: *file タイプは DataWriter インタフェースを実装していません (WriteData メソッドが欠落しています)。
WriteDataX メソッド自体の署名は正当です。しかし、コンパイラがコードの 33 行目をスキャンすると、*file タイプを DataWriter に割り当てようとするときに、*file タイプが DataWriter インターフェイスを完全に実装しているかどうかを確認する必要があることがわかります。どうやら、DataWriter に必要な WriteData() メソッドが見つからないため、コンパイラがエラーをスローしているようです。
2) インターフェイスを実装するメソッド シグネチャの不一致によって発生するエラー
変更したコードを復元した後、WriteData() メソッドを再度変更して、データ パラメータの型をinterface{} から int 型に変更してみます。コードは次のようになります。
func (d *file) WriteData(data int) error {
コードをコンパイルしてエラーを報告します。
cannot use f (type *file) as type DataWriter in assignment:
*file does not implement DataWriter (wrong type for WriteData method)
have WriteData(int) error
want WriteData(interface {}) error
今回、DataWriter を実装しない理由は、(WriteData() メソッドのタイプが間違っています) found WriteData(int) error, Expected WriteData(interface{}) error になります。
この方法で報告されるエラーは、実装者のメソッド シグネチャとインターフェイスのメソッド シグネチャの不一致が原因で発生します。
インターフェイスが実装されるための 2 番目の条件: インターフェイス内のすべてのメソッドが実装される
インターフェイスに複数のメソッドがある場合、これらのメソッドがすべて実装されている場合にのみ、インターフェイスをコンパイルして正しく使用できます。
このセクションの冒頭のコードでは、DataWriter にメソッドを追加します。コードは次のとおりです。
// 定义一个データライター
type DataWriter interface {
WriteData(data interface{}) error
// 書き込み可能かどうか
CanWrite() bool
}
ブール値を返す CanWrite() メソッドを追加しました。この時点で、コードを再度コンパイルしてエラーを報告します。
cannot use f (type *file) as type DataWriter in assignment:
*file does not implement DataWriter (missing CanWrite method)
DataWriter() を通常に使用するには、ファイルに CanWrite() メソッドを実装する必要があります。
Go 言語のインターフェイス実装は暗黙的であり、インターフェイスを実装する型がどのインターフェイスを実装するかを記述する必要はありません。この設計は非侵入型設計と呼ばれます。
メソッドを実装するとき、どのメソッドが将来インターフェイスになるかを予測することはできません。インターフェイスが作成され、そのインターフェイスを実装するために古いコードが必要になると、古いコードの派生部分を変更する必要があり、一般に再コンパイルが雪崩のように発生します。
ヒント
従来の派生インターフェイスとクラス関係構築モードでは、型が強く結合された親子関係を持つことができます。この関係は、一般に「クラス派生図」の形で行われます。大規模なソフトウェアでは、非常に複雑な派生ツリーが存在することは珍しくありません。システムの機能が増加し続けるにつれて、この「導出ツリー」はますます複雑になります。
Go 言語の場合、非侵入的な設計により、あらゆる種類の実装者を並列して組み合わせることができます。結合方法はコンパイル時にユーザーが確認することになります。したがって、GO言語を使用する場合、「クラス派生グラフ」を持つ必要はなく、持つことも不可能であり、開発者が注意しなければならないのは、「何が必要なのか」「何が実現できるのか」だけです。 。