Neden * Arayüzüne * * Yapı atayamam?


142

Sadece Go turunda çalışıyorum ve işaretçiler ve arayüzler hakkında kafam karıştı. Bu Go kodu neden derlenmiyor?

package main

type Interface interface {}

type Struct struct {}

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

    _, _ = pi, ps
}

yani eğer Structbir olduğunu Interface, neden olmaz *Structbir olmak *Interface?

Aldığım hata mesajı:

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


arayüzler örtük işaretçiler gibi davranabilir ...
Victor

oyun alanınızı zenginleştirmenizi 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 }ve kendi sonuçlarınızı çıkarmanızı önerebilir miyim
Victor

Yanıtlar:


183

Bir arabirimi uygulayan bir yapınız varsa, o yapıya bir işaretçi de o arabirimi otomatik olarak uygular. Bu nedenle *SomeInterface, işlevlerin prototipinde hiç bulunmadınız , çünkü bu hiçbir şey eklemeyecektir SomeInterfaceve değişken bildirimde böyle bir türe ihtiyacınız yoktur ( bu ilgili soruya bakın ).

Bir arayüz değeri, somut yapının değeri değildir (değişken bir boyuta sahip olduğu için, bu mümkün olmaz), ancak bir tür işaretçi (yapıya daha kesin bir işaretçi ve tipe bir işaretçi olmak) ). Russ Cox tam olarak burada anlatıyor :

Arabirim değerleri, arabirimde depolanan tür hakkında bir işaretçi ve ilişkili verilere bir işaretçi veren iki sözcüklü bir çift olarak temsil edilir.

resim açıklamasını buraya girin

Bu nedenle Interface, *Interfacebir yapı uygulamasına yönelik bir işaretçi tutmak için doğru türde değildir Interface.

Yani sadece

var pi Interface

8
Tamam, bence bu bana mantıklı geliyor. Sadece nedenini merak ediyorum (bu durumda), sadece derleme zamanı hatası değil var pi *Interface.
Simon Nickerson

1
Açıklamak için daha fazla ayrıntıya girdim. Bkz. Düzenleme. Bağlantı verdiğim Russ Cox makalesinin okunmasını öneriyorum.
Denys Séguret

1
Bu sadece C veya C ++ 'da asla yapamadığım bir şekilde işaretçiler
anlamama

2
Tamam, neden anlamıyorum *SomeInterfacesadece neden derleme hatası değil?
sazary

2
@charneykaye Burada tamamen doğru değilsiniz. Bir arabirim değişkeni bildirirken veya işlev bildiriminin bir parçası olarak arabirim türü döndürürken asla * SomeInterface öğeniz olmaz . Ancak , bir işlevin parametreleri içinde * SomeInterface öğesine sahip olabilirsiniz .
arauter

7

Belki de bunu demek istediniz:

package main

type Interface interface{}

type Struct struct{}

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

        _, _ = pi, ps
}

Tamam derler. Ayrıca buraya bakınız .


Bu kabul edilmelidir, diğeri soruya gerçekten cevap vermez.
DrKey


0

Im interface{}sadece eventsI interface{}bağımsız değişken olarak tüketirken im aşağıdaki şekilde kullanarak, hala aşağıda gördüğünüz gibi bir Struct Pointers göndermek mümkün.

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)

Şimdi storyboard.godosya oluşturma fonksiyonu içinde

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
}

Yukarıda görebileceğiniz gibi Storyboard.go sadece tüketiyor Events []interface{}ama aslında Gönderiyorum bir Yapısal işaretçi ve iyi çalışıyor.

burada başka bir örnek daha

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.