* Structを* Interfaceに割り当てることができないのはなぜですか?


142

私はGoツアーを進めているだけですが、ポインタとインターフェースについて混乱しています。このGoコードがコンパイルされないのはなぜですか?

package main

type Interface interface {}

type Struct struct {}

func main() {
    var ps *Struct
    var pi *Interface
    pi = ps

    _, _ = pi, ps
}

つまり、Structがである場合Interface、なぜがにならない*Struct*Interfaceですか?

私が得るエラーメッセージは:

prog.go:10: cannot use ps (type *Struct) as type *Interface in assignment:
        *Interface is pointer to interface, not interface


インターフェイスは暗黙のポインタのように動作するように見えます...
ビクター

あなたの遊び場を豊かにしfunc main() { var ps *Struct = new(Struct) var pi *Interface var i Interface i = ps pi = &i fmt.Printf("%v, %v, %v\n", *ps, pi, &i) i = *ps fmt.Printf("%v, %v, %v\n", *ps, pi, i) _, _, _ = i, pi, ps }て、あなた自身の結論を出すことをお勧めします
ビクター

回答:


183

インターフェイスを実装する構造体がある場合、その構造体へのポインターは、そのインターフェイスも自動的に実装します。これ*SomeInterfaceが関数のプロトタイプに含まれない理由です。これは何も追加SomeInterfaceせず、変数宣言でそのような型を必要としません(この関連する質問を参照)。

インターフェイスの値は具体的な構造体の値ではありません(可変サイズのため、これは不可能です)が、一種のポインターです(より正確には、構造体へのポインターと型へのポインター) )。ラス・コックスはそれをここで正確に説明しています

インターフェイス値は、インターフェイスに格納されているタイプに関する情報へのポインタと関連データへのポインタを提供する2ワードのペアとして表されます。

ここに画像の説明を入力してください

これが理由Interfaceであり*Interface、実装する構造体へのポインタを保持するのに適切な型ではありませんInterface

したがって、単に使用する必要があります

var pi Interface

8
OK、それは私には理にかなっていると思います。なぜ(その場合)と思うのは、単にコンパイル時のエラーではないということvar pi *Interfaceです。
Simon Nickerson

1
私はそれを説明するために詳細に行きました。編集を参照してください。リンクしているRuss Coxの記事を読むことをお勧めします。
DenysSéguret

1
これはちょうど私が私がなかったように、ポインタの意味を作るのを助け決してこのエレガントでシンプルな説明をありがとうございました:-) ... CまたはC ++で行うことができる
mindplay.dk

2
了解しました。なぜ*SomeInterfaceコンパイルエラーではないのですか?
sazary 2016年

2
@charneykayeあなたはここでは完全に正しいわけではありません。インターフェイス変数を宣言するとき、または関数宣言の一部としてインターフェイスタイプを返すときは、* SomeInterfaceはありません。ただし、関数のパラメーター内に* SomeInterfaceを含めることができます
arauter、2017

7

これはおそらくあなたが意味したことです:

package main

type Interface interface{}

type Struct struct{}

func main() {
        var ps *Struct
        var pi *Interface
        pi = new(Interface)
        *pi = ps

        _, _ = pi, ps
}

OKコンパイルします。こちらもご覧ください


これは受け入れられるべきであり、他の人は実際には質問に答えません。
DrKey


0

私は次の方法を使用していますinterface{}eventsI interface{}、引数として消費していますが、以下に示すように、構造体ポインタを送信することができます。

func Wait(seconds float64) *WaitEvent {
    return WaitEventCreate(seconds)
}

main.go

var introScene = []interface{}{
        storyboard.Wait(5),
        storyboard.Wait(2),
    }

    var storyboardI = storyboard.Create(stack, introScene)
    stack.Push(&storyboardI)

storyboard.goファイル作成関数内

type Storyboard struct {
    Stack  *gui.StateStack
    Events []interface{} //always keep as last args
}

func Create(stack *gui.StateStack, eventsI interface{}) Storyboard {
    sb := Storyboard{
        Stack: stack,
    }

    if eventsI != nil {
        events := reflect.ValueOf(eventsI)
        if events.Len() > 0 {
            sb.Events = make([]interface{}, events.Len())
            for i := 0; i < events.Len(); i++ {
                sb.Events[i] = events.Index(i).Interface()
            }
        }
    }

    return sb
}

上の図からわかるように、Storyboard.goは消費してEvents []interface{}いますが、実際のIm送信はStructポインターであり、正常に機能します。

ここにもう一つの例

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.