Mengapa saya tidak dapat menetapkan * Struct ke * Interface?

142

Saya hanya bekerja melalui tur Go , dan saya bingung tentang pointer dan antarmuka. Mengapa kode Go ini tidak dikompilasi?

package main

type Interface interface {}

type Struct struct {}

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

    _, _ = pi, ps
}

yaitu jika Structadalah Interface, mengapa tidak *Structmenjadi *Interface?

Pesan kesalahan yang saya dapatkan adalah:

prog.go:10: cannot use ps (type *Struct) as type *Interface in assignment:
        *Interface is pointer to interface, not interface
Simon Nickerson
sumber
sepertinya antarmuka bisa berperilaku seperti petunjuk implisit ...
Victor
bolehkah saya sarankan untuk memperkaya taman bermain Anda 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 }dan membuat kesimpulan sendiri
Victor

Jawaban:

183

Ketika Anda memiliki struct yang mengimplementasikan antarmuka, pointer ke struct yang mengimplementasikan antarmuka itu secara otomatis juga. Itu sebabnya Anda tidak pernah memiliki *SomeInterfaceprototipe fungsi, karena ini tidak akan menambah apa pun SomeInterface, dan Anda tidak perlu jenis semacam itu dalam deklarasi variabel (lihat pertanyaan terkait ini ).

Nilai antarmuka bukan nilai struct beton (karena memiliki ukuran variabel, ini tidak akan mungkin), tetapi itu adalah jenis pointer (lebih tepatnya pointer ke struct dan pointer ke tipe ). Russ Cox menjelaskannya di sini :

Nilai antarmuka direpresentasikan sebagai pasangan dua kata yang memberikan penunjuk ke informasi tentang tipe yang disimpan dalam antarmuka dan penunjuk ke data terkait.

masukkan deskripsi gambar di sini

Inilah sebabnya Interface, dan bukan *Interfacetipe yang tepat untuk memegang pointer ke implementasi struct Interface.

Jadi, Anda harus menggunakan

var pi Interface
Denys Séguret
sumber
8
OK, saya pikir itu masuk akal bagi saya. Saya hanya ingin tahu mengapa (dalam hal ini), itu bukan hanya kesalahan waktu kompilasi untuk mengatakan var pi *Interface.
Simon Nickerson
1
Saya pergi ke rincian lebih lanjut untuk menjelaskannya. Lihat edit. Saya sarankan membaca artikel Russ Cox yang saya tautkan.
Denys Séguret
1
Ini hanya membantu saya memahami petunjuk dengan cara yang tidak pernah dapat saya lakukan dalam C atau C ++ ... terima kasih banyak untuk penjelasan yang elegan dan sederhana ini :-)
mindplay.dk
2
Baiklah, saya masih belum mengerti mengapa *SomeInterfacebukan hanya kesalahan kompilasi?
sazary
2
@ charneykaye Anda tidak sepenuhnya benar di sini. Anda tidak pernah memiliki * SomeInterface ketika mendeklarasikan variabel antarmuka atau ketika mengembalikan jenis antarmuka sebagai bagian dari deklarasi fungsi . Namun Anda dapat memiliki * SomeInterface dalam parameter fungsi .
arauter
7

Ini mungkin yang Anda maksud:

package main

type Interface interface{}

type Struct struct{}

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

        _, _ = pi, ps
}

Kompilasi OK. Lihat juga di sini .

zzzz
sumber
Ini harus diterima, yang lain tidak benar-benar menjawab pertanyaan.
DrKey
0

Berikut adalah cara yang sangat sederhana untuk menetapkan struct ke antarmuka:

package main

type Interface interface{}

type Struct struct{}

func main() {
    ps := new(Struct)
    pi := Interface(ps)

    _, _ = pi, ps
}

https://play.golang.org/p/BRTaTA5AG0S

Miguel Mota
sumber
0

Saya menggunakan cara berikut interface{}sementara saya hanya mengkonsumsi eventsI interface{}sebagai argumen, saya masih dapat mengirim Struct Pointer seperti yang Anda lihat di bawah.

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)

Sekarang di dalam storyboard.gofile Buat fungsi

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
}

Seperti yang dapat Anda lihat di atas Storyboard.go hanya memakan waktu Events []interface{}tetapi sebenarnya pengiriman Im adalah pointer Struct dan berfungsi dengan baik.

contoh lain di sini

BAJA
sumber