1. ホーム
  2. go

[解決済み] interface{}の意味は?

2022-04-27 08:58:32

質問事項

私はインターフェイスの初心者で、以下の方法でSOAPリクエストを行おうとしています。 ギズーブ

の意味がわからない。

Msg interface{}

をこのコードの中に入れてください。

type Envelope struct {
    Body `xml:"soap:"`
}

type Body struct {
    Msg interface{}
}

に同じ構文があることを確認しました。

fmt.Println

が何を実現するのか理解できません。

interface{}

解決方法は?

注:Go 1.18 (Q1 2022)では、以下のようにリネームされます。 interface{} から any (のエイリアス)。 interface{} ).

参照 49884号 , CL 368254 および コミット2580d0e .

この回答の最後の部分を参照してください。


記事"を参考にするとよいでしょう。 Goでインターフェイスを使う方法 "(ベースは" Russ Coxによるインターフェイスの説明 ")。

インターフェース

インターフェースとは、2つのものです。

  • は、メソッドのセットです。
  • しかし、それはまた、タイプである

interface{} 型(または any Go 1.18+の場合) では 空のインターフェイス は、メソッドを持たないインターフェースです。

implementsキーワードがないため、すべての型は少なくとも0個のメソッドを実装し、インターフェイスを満たすことは自動的に行われます。 すべての型は空のインターフェイスを満たす .

ということは、もしあなたが interface{} の値をパラメータとします。 その関数に任意の値を与えることができます。 .

(それは Msg は、ご質問の「任意の値」を表しています。)

func DoSomething(v interface{}) {
   // ...
}


func DoSomething(v any) {
   // ...
}

ここで、混乱が生じます。

の内部には DoSomething 関数を使用します。 とは v の型は?

初心者のゴキちゃんは、" v は任意の型である」とありますが、これは間違いです。

v はどの型でもない。 である。 interface{} タイプ .

に値を渡すと DoSomething 関数を呼び出すと、Goランタイムは 型変換 (必要な場合)、および に変換します。 interface{} .

すべての値は、実行時に正確に1つの型を持ちます。 v の1つの静的な型は interface{} (または any Go 1.18+の場合)。

インターフェース値は、2つの単語のデータで構成されています。 :

  • は、値の基礎となる型のメソッド・テーブルを指すために使われる単語です。
  • もう1つの単語は、その値が保持している実際のデータを指すために使用されます。

追記:インターフェイスの構造については、Russの記事がかなり完成度の高いものでした。

type Stringer interface {
    String() string
}

インターフェースの値は、インターフェースに格納されている型に関する情報へのポインタと、関連するデータへのポインタの2語の組で表現されます。

Stringer型のインターフェース値にbを代入すると、インターフェース値の両方の単語が設定されます。

インターフェース値の最初の単語は、私がインターフェーステーブルまたはイタブルと呼んでいるものを指しています。 (ランタイムソースでは、C言語の実装名はItabです)。

itableは、関係する型に関するいくつかのメタデータから始まり、関数ポインタのリストになる。

itableは動的型ではなく、インターフェース型に対応することに注意してください。 .

この例でいうと Stringer 保持型Binaryは、Stringerを満たすために使用されるメソッドをリストアップしており、それは単に String : バイナリーの他のメソッド( Get には登場しません。 itable .

インターフェース値の2番目の単語は、実際のデータを指しています のコピーで、この場合は b .

課題 var s Stringer = b のコピーを作成します。 b を指すのではなく b と同じ理由で var c uint64 = b はコピーを作成します: if b を後で変更します。 sc は、新しい値ではなく、元の値を持つことになっています。

インターフェースに格納される値は任意に大きくなる可能性がありますが、インターフェース構造体では値を保持するために1ワードだけが専用に使用されます。したがって、代入はヒープ上にメモリの塊を確保し、ポインタを1ワードのスロットに記録します。


課題33232 を指摘しているようです。 any のエイリアスとして interface{} Go 1.18 (2022年第1四半期) に含まれる

ラス・コックスの説明 :

  1. ' any が制約のためだけであることは、書籍やブログ記事など、ジェネリックのすべての記述にある詳細です。 最終的にそれを許可する可能性が高いと思われる場合、最初からそれを許可し、すべての書かれた資料を無効にすることを避けることは理にかなっています。

  2. ' any が制約のためだけにあることは、概念の一般性と直交性を低下させる思わぬ切り口です。 待ってみましょう」と言うのは簡単ですが、用途を規定することは、完全な一般性よりもはるかにギザギザした特徴を作り出す傾向があります。私たちは、このことを型のエイリアスでも経験しました(そして、ありがたいことに、提案されたほとんどすべての切り出しに抵抗しました)。

  3. もし、' any がジェネリックコードで許可され、非ジェネリックコードでは許可されない場合、ジェネリックを過剰に使用することを助長する可能性があるため、単に' any よりも書きやすい。 interface{} ジェネリックかどうかの判断は、本当は他の要素を考慮して行うべきなのに。

  4. を許可すると、' any を使用することもできます。 interface{} は、そのコードがジェネリックス以前のものであり、ポストジェネリックスの世界ではまだ再考されていないことを示す一種のシグナルとして機能する可能性があります。 あるコードでは interface{} はジェネリックスを使うべきでしょう。他のコードはインターフェイスを使い続けるべきです。

    というテキストを削除するために、何らかの方法で書き換えること。 interface{} もちろん、ジェネリックスを使った方が良いコードでも、まだ interface{} 後方互換性の理由から、しかし、その決定が検討されなされたことを確認するために、更新することができます)。

また、そのスレッドには について説明しています。 interface{} :

これは特別な設計ではなく、Goの型宣言のシンタックスの論理的な帰結なのです。

0個以上のメソッドを持つ無名インターフェースを使用することができます。

func f(a interface{Foo(); Bar()}) {
   a.Foo()
   a.Bar()
}

無名構造体を型が必要な場所で使用する方法と似ています。

func f(a struct{Foo int; Bar string}) {
   fmt.Println(a.Foo)
   fmt.Println(a.Bar)
}

すべての型は少なくとも0個のメソッドを持っているので、空のインターフェイスは偶然にもすべての型にマッチするのです。

削除する interface{} は、一貫性を保ちたい/特殊なケースを導入したくない場合、言語からすべてのインターフェイス機能を削除することを意味します。