GoEmptyインターフェイスの説明

インターフェース、インターフェース{}、変換

Goのインターフェースはメソッドセット。このメソッドセットを実装するタイプは、次のように言われます。インターフェイスを実装する

インターフェイスは暗黙的に実装されます。ありません実装キーワード、他の言語で使用されます。タイプがインターフェイスのメソッドセット全体を定義する場合、それを実装します。これは構造型と呼ばれ、コンパイル時の同等物です。ダックタイピング

アヒルのように歩き、アヒルのように泳ぎ、アヒルのように鳴くなら、それはアヒルです

重要:Goでは、インターフェースはデータではなく一連のメソッド(アクション)を抽象化します。

次の例はGoでインターフェースを使用する方法は、話すことができる動物の基本的なインターフェイスと、インターフェイスを満たすさまざまな構造体を示しています。

type Animal interface {
    Speak() string
}

type Dog struct { }

func (d Dog) Speak() string { return “Woof!” }

type Cat struct { }

func (c Cat) Speak() string { return “Meow!” }

type Llama struct { }

func (l Llama) Speak() string { return “???” }

type JavaProgrammer struct { }

func (j JavaProgrammer) Speak() string { return “Design patterns!” }

[]動物を作成して実行できますSpeak()その内容について:

func main() {
    animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}
    for _, animal := range animals {
        fmt.Println(animal.Speak())
    }
}

演奏する

空のインターフェース

ザ・Animalインターフェースは小さくて素敵ですが、初心者にはもっと単純で、それでもやや複雑な概念があります。それは空のインターフェースです。

interface{}重要な概念であるGoemptyインターフェースです。すべてのタイプは、定義によりそれを実装します。

インターフェイスはタイプであるため、次のように定義できます。

type Dog struct {
    Age interface{}
}

また、空のインターフェイスタイプを関数パラメータとして渡すこともできます。

func Eat(t interface{}) {
    // ...
}

受け入れるinterface{}関数が任意の型を受け入れることを意味するのではなく、Eatが次の値を受け入れることを意味します。interface{}タイプ。

実行時に、Goは渡された実際の値をに変換しますinterface{}値。

タイプを使用して構造体のフィールドを定義する場合interface{}、任意のタイプの値を割り当てることができます。例えば:

package main

import “fmt”

type Dog struct { Age interface{} }

func main() { dog := Dog{} dog.Age = “3” fmt.Printf("%#v %T\n", dog.Age, dog.Age)

<span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span> = <span style="color:#ae81ff">3</span>
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">"%#v %T\n"</span>, <span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span>, <span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span>)

<span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span> = <span style="color:#e6db74">"not really an age"</span>
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">"%#v %T"</span>, <span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span>, <span style="color:#a6e22e">dog</span>.<span style="color:#a6e22e">Age</span>)

}

演奏する

プリント

"3" string
3 int
"not really an age" string

もちろん、これは基本的なタイプに限定されません。スライス、マップ、カスタム構造体をそこに格納できます。

インターフェイスが内部でどのように表されるか

内部的には、インターフェース2つですwords、バイトのセット。

1つの単語は、型の基礎となる値を指します。一言でデータを指します。

変換

やったときanimals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}}以前は、Goはすべての特定の動物タイプを自動的に動物タイプに変換していました。そのスライスのすべての要素は現在、タイプAnimalであり、基になるタイプは、Dog、Cat、Llamaなどの特定の種を指しています。

しかし、メソッドが受け入れる場合[]interface{}たとえば、私たちはただ渡すことはできませんanimalsタイプが一致しないため、それに。必要があるそれぞれを明示的に変換するAnimalinterface{}前に、ループで、[] Tを[]インターフェース{}に変換できますかよくある質問:

t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
    s[i] = v
}

の基になるタイプを決定しますinterface{}

値がタイプの場合interface{}、基になる型を判別することをお勧めします。どうやって?スイッチをオンにした状態.(type)、 お気に入り効果的な囲碁説明:

スイッチを使用して、インターフェイス変数の動的タイプを検出することもできます。このようなタイプスイッチは、括弧内にキーワードタイプを含むタイプアサーションの構文を使用します。スイッチが式で変数を宣言する場合、変数は各句で対応するタイプになります。このような場合に名前を再利用することも慣用的であり、事実上、同じ名前であるがそれぞれの場合で異なる型の新しい変数を宣言します。

var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
    fmt.Printf("unexpected type %T\n", t)     // %T prints whatever type t has
case bool:
    fmt.Printf("boolean %t\n", t)             // t has type bool
case int:
    fmt.Printf("integer %d\n", t)             // t has type int
case *bool:
    fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
    fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}

その他のチュートリアル: