Go 言語は、型アサーションを使用してインターフェイス型を実行できます。 Go では、あるインターフェイス型を別のインターフェイス型に変換する場合でも、インターフェイスを別の基本型に変換する場合でも、型アサーションを使用する必要があります。「変換された変数: = インターフェイス変数。(ターゲット型)」という 2 種類の変換構文があります。および「変換された変数、ok := インターフェイス変数。(ターゲットの型)」。
このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。
Golang では、あるインターフェイス型を別のインターフェイス型に変換したり、インターフェイスを別の基本型に変換したりするには、Type アサーション を使用する必要があります。
型アサーションの形式
型アサーションは、インターフェイス値に対して使用される操作です。構文的には、i.(T) はアサーション タイプと呼ばれるように見えます。ここで、i はインターフェイス タイプを表し、T はタイプを表します。型アサーションは、操作対象のオブジェクトの動的型がアサートされた型と一致するかどうかをチェックします。
型アサーションの基本形式は次のとおりです。
t := i.(T)
ここで、i はインターフェイス変数を表し、T は変換されたターゲットの型を表し、t は変換された変数を表します。
ここでは 2 つの可能性があります。まず、アサートされた型 T が具象型の場合、型アサーションは i の動的型が T と同じかどうかをチェックします。このチェックが成功すると、型アサーションの結果は i の動的な値になります。これはもちろん型 T です。つまり、具象型の型アサーションは、そのオペランドから具象値を取得します。チェックが失敗すると、後続の操作でパニックが発生します。例:
var w io.Writer w = os.Stdout f := w.(*os.File) // 成功: f == os.Stdout c := w.(*bytes.Buffer) // 死机:接口保存*os.file,而不是*bytes.buffer
Second、アサートされた型 T がインターフェイス型の場合、型アサーションは i の動的型が T を満たすかどうかをチェックします。このチェックが成功した場合、動的値は取得されません。結果は同じ型と値部分を持つインターフェイス値のままですが、結果の型は T になります。つまり、インターフェイス型の型アサーションは、型の表現方法を変更し、利用可能なメソッドのセット (通常はより大きい) を変更しますが、インターフェイス値の動的な型と値の部分は保護されます。
以下の最初の型アサーションの後、w と rw は両方とも os.Stdout を保持するため、それぞれ動的型 *os.File を持ちますが、変数 w は外部にのみ公開される io.Writer 型です。ファイルの Write メソッドは公開されますが、rw 変数は Read メソッドのみを公開します。
var w io.Writer w = os.Stdout rw := w.(io.ReadWriter) // 成功:*os.file具有读写功能 w = new(ByteCounter) rw = w.(io.ReadWriter) // 死机:*字节计数器没有读取方法
アサーション操作のオブジェクトが nil インターフェイス値の場合、アサートされる型に関係なく、型アサーションは失敗します。 nil インターフェイス値を除いて、代入操作のように動作するため、制限の少ないインターフェイス タイプ (メソッドのセットが少ない) をアサートする必要はほとんどありません。
T インターフェイスのメソッドを完全に実装していない場合、このステートメントはクラッシュを引き起こします。ダウンタイムを引き起こすのはあまり好ましくないので、上記のステートメントを記述する別の方法があります:
t,ok := i.(T)
この方法では、インターフェイスが実装されていない場合、ok は false に設定され、t は に設定されます。タイプ T の 0。値。通常の実装では、ok は true です。ここでの ok は、インターフェイス i が型 T を実装するかどうかの結果と考えることができます。
#インターフェースを他のインターフェースに変換する
#あるインターフェースを実装する型は、別のインターフェースも実装します。このとき、2 つのインターフェースは間の変換が可能です。
鳥と豚には異なる特性があり、鳥は飛べますが、豚は飛べませんが、どちらの動物も歩くことができます。構造体を使用して鳥と豚を実装する場合、独自の特性を与える Fly() メソッドと Walk() メソッドを使用すると、鳥と豚にそれぞれ飛行動物インターフェイス (Flyer) と歩行動物インターフェイス (Walker) を実装できます。
鳥と豚のインスタンスが作成された後、それらはインターフェース タイプのマップに保存されます。{} Interface{} タイプは空のインターフェースを表します。つまり、このインターフェースは任意のタイプとして保存できます。 Bird または Pig のインスタンスを保持するインターフェース{} 変数に対してアサーション操作を実行します。アサーション オブジェクトがアサーションで指定されたタイプの場合は、アサーション オブジェクトのタイプに変換されたインターフェースが返されます。指定されたアサーション タイプでない場合は、アサーション オブジェクトのタイプに変換されたインターフェースが返されます。の場合、アサーションの 2 番目のパラメーターは false を返します。
たとえば、次のコード:
var obj interface = new(bird) f, isFlyer := obj.(Flyer)
コード内では、new(bird) は *bird 型の Bird インスタンスを生成し、このインスタンスは、interface{ 型の obj 変数に保存されます。 }。 obj.(Flyer) 型アサーションを使用して、obj を Flyer インターフェイスに変換します。 f は変換が成功した場合の Flyer インターフェイスの型で、isFlyer は変換が成功したかどうかを示し、型は bool です。
以下は詳細なコード (コード 1) です。
package main import "fmt" // 定义飞行动物接口 type Flyer interface { Fly() } // 定义行走动物接口 type Walker interface { Walk() } // 定义鸟类 type bird struct { } // 实现飞行动物接口 func (b *bird) Fly() { fmt.Println("bird: fly") } // 为鸟添加Walk()方法, 实现行走动物接口 func (b *bird) Walk() { fmt.Println("bird: walk") } // 定义猪 type pig struct { } // 为猪添加Walk()方法, 实现行走动物接口 func (p *pig) Walk() { fmt.Println("pig: walk") } func main() { // 创建动物的名字到实例的映射 animals := map[string]interface{}{ "bird": new(bird), "pig": new(pig), } // 遍历映射 for name, obj := range animals { // 判断对象是否为飞行动物 f, isFlyer := obj.(Flyer) // 判断对象是否为行走动物 w, isWalker := obj.(Walker) fmt.Printf("name: %s isFlyer: %v isWalker: %v\n", name, isFlyer, isWalker) // 如果是飞行动物则调用飞行动物接口 if isFlyer { f.Fly() } // 如果是行走动物则调用行走动物接口 if isWalker { w.Walk() } } }
コードの説明は次のとおりです。
行 6 は、空を飛ぶ動物。
行 11 は、歩く動物のインターフェイスを定義します。
行 16 と行 30 はそれぞれ鳥と豚のオブジェクトを定義し、それぞれ飛行動物と歩行動物のインターフェイスを実装しています。
行 41 はオブジェクト名とオブジェクト インスタンスをマッピングするマップで、インスタンスは鳥と豚です。
行 47 はマップの移動を開始します。obj はインターフェースのタイプです。{}
第 50 行中,使用类型断言获得 f,类型为 Flyer 及 isFlyer 的断言成功的判定。
第 52 行中,使用类型断言获得 w,类型为 Walker 及 isWalker 的断言成功的判定。
第 57 和 62 行,根据飞行动物和行走动物两者是否断言成功,调用其接口。
代码输出如下:
将接口转换为其他类型
在代码 1 中,可以实现将接口转换为普通的指针类型。例如将 Walker 接口转换为 *pig 类型,请参考下面的代码:
p1 := new(pig) var a Walker = p1 p2 := a.(*pig) fmt.Printf("p1=%p p2=%p", p1, p2)
对代码的说明如下:
第 3 行,由于 pig 实现了 Walker 接口,因此可以被隐式转换为 Walker 接口类型保存于 a 中。
第 4 行,由于 a 中保存的本来就是 *pig 本体,因此可以转换为 *pig 类型。
第 6 行,对比发现,p1 和 p2 指针是相同的。
如果尝试将上面这段代码中的 Walker 类型的 a 转换为 *bird 类型,将会发出运行时错误,请参考下面的代码:
p1 := new(pig) var a Walker = p1 p2 := a.(*bird)
运行时报错:
panic: interface conversion: main.Walker is *main.pig, not *main.bird
报错意思是:接口转换时,main.Walker 接口的内部保存的是 *main.pig,而不是 *main.bird。
因此,接口在转换为其他类型时,接口内保存的实例对应的类型指针,必须是要转换的对应的类型指针。
总结
接口和其他类型的转换可以在Go语言中自由进行,前提是已经完全实现。
接口断言类似于流程控制中的 if。但大量类型断言出现时,应使用更为高效的类型分支 switch 特性。
以上がGo言語のインターフェースタイプを変換する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。