{} Arayüzünün anlamı nedir?


135

Arayüzlerde yeniyim ve github tarafından SOAP isteği yapmaya çalışıyorum

Anlamını anlamıyorum

Msg interface{}

bu kodda:

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

type Body struct {
    Msg interface{}
}

Aynı sözdizimini şurada gözlemledim:

fmt.Println

ama neyin başarıldığını anlamayın

interface{}

20
interface{}az ya da çok eşdeğerdir void *C. Herhangi bir şey işaret edebilir ve bunu kullanmak için bir döküm / tür iddiasını gerekir.
Nick Craig-Wood

{} Arayüzünün anlamı nedir? Stackoverflow.com/a/62337836/12817546 adresine bakın .
Tom J

Yanıtlar:


191

" Go'da arabirimler nasıl kullanılır " makalesine başvurabilirsiniz (" Russ Cox'un arabirim tanımına " dayanarak ):

Ne olduğunu bir arayüz?

Arayüz iki şeydir:

  • bir dizi yöntemdir,
  • ama aynı zamanda bir tür

interface{}Tipi, boş arayüz hiçbir yöntemleri vardır arayüzüdür.

Hiçbir uygulama anahtar sözcüğü olmadığından, tüm türler en az sıfır yöntem uygular ve bir arabirimi tatmin etmek otomatik olarak yapılır, tüm türler boş arabirimi tatmin eder .
Bu interface{}, parametre olarak bir değer alan bir işlev yazarsanız, bu işlevi herhangi bir değerle sağlayabileceğiniz anlamına gelir .

(Sorunuzda Msgtemsil eden şey budur : herhangi bir değer)

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

İşte burada kafa karıştırıcı hale geliyor:

DoSomethingfonksiyonu, nedir v'ın türü?

Yeni başlayanlar, " vherhangi bir türden" olduğuna inanmaya yönlendirilir , ancak bu yanlıştır.
vherhangi bir türde değildir; o taşımaktadır interface{}türü .

İşleve bir değer iletirken, DoSomethingGo çalışma zamanı bir tür dönüşümü gerçekleştirir (gerekirse) ve değeri bir interface{}değere dönüştürür .
Tüm değerlerin çalışma zamanında tam olarak bir türü vardır ve vstatik türlerinden biri interface{}.

Arayüz değeri iki kelimelik veriden oluşur :

  • değerin temel türü için bir yöntem tablosuna işaret etmek için bir kelime kullanılır,
  • ve diğer kelime, bu değer tarafından tutulan gerçek verilere işaret etmek için kullanılır.

Ek: Bu, Russ'ın bir arayüz yapısıyla ilgili makalesi oldukça eksiksizdi:

type Stringer interface {
    String() string
}

Arayüz değerleri, arayüzde depolanan tip hakkındaki bilgilere bir işaretçi ve ilişkili verilere bir işaretçi veren iki kelimeli bir çift olarak temsil edilir.
Stringer türünde bir arabirim değerine b atanması arabirim değerinin her iki sözcüğünü de ayarlar.

http://research.swtch.com/gointer2.png

Arayüz değerindeki ilk kelime, arayüz tablosu veya itable dediğim şeyi işaret ediyor (i-table olarak telaffuz edilir; çalışma zamanı kaynaklarında, C uygulama adı Itab'dir).
İtable, ilgili türlerle ilgili bazı meta verilerle başlar ve ardından işlev işaretçilerinin bir listesi haline gelir.
İtable'ın dinamik türe değil arayüz tipine karşılık geldiğini unutmayın .
Örneğimiz açısından, itable for Stringerholding type Binary Stringer'ı tatmin etmek için kullanılan yöntemleri listeler, bu sadece String: Binary'nin diğer yöntemleri ( Get) itable.

Arayüz değerindeki ikinci kelime , bu durumda bir kopyası olan gerçek verileri işaret ederb .
Atama var s Stringer = bbir kopyasını yapar byerine kendi noktayı baynı nedenle var c uint64 = bbir kopyasını yapar: eğer bdaha sonraki değişiklikler sve cözgün değer, değil, yeni olanı gerekiyordu.
Arabirimlerde depolanan değerler keyfi olarak büyük olabilir, ancak arabirim yapısındaki değeri tutmak için yalnızca bir sözcük adanmıştır, bu nedenle atama, yığın üzerinde bir bellek yığını ayırır ve işaretçiyi tek sözcüklük yuvaya kaydeder.


4
"İki kelimelik veri" ile neyi kastediyorsunuz? Özellikle, "kelime" ne anlama geliyor?
Mingyu

3
@Mingyu Bu iki kelimeyi göstermek için cevabı tamamladım (32 bitlik puan).
VonC

2
@Mingyu: VonC, bilgisayar mimarisi anlamında bir kelimeye atıfta bulunuyor - sabit boyutlu bir veri parçasını tanımlayan bir bitler topluluğu. Kelime boyutu, kullandığınız işlemci mimarisine göre belirlenir.
Dan Esparza

1
Cevabınız için teşekkürler @VonC ... Doğru olan şu ki, bir şeyler sorduğumda merkeze gitmekten yoruldum .. insanlar çoğu zaman bana dokümanları okumam gerektiğini söylüyor ... eğer hissedersem önerinizi hatırlayacağım bunun için düzgün bir gönderi yazacağım ... ama sormanın başka bir yolunu gerçekten düşünemiyorum. Bu yüzden yine de teşekkürler ve düşük irademi affedin. Neden sormaktan hoşlanmadığımı açıklığa kavuşturmak için şuna bir göz atabilirsiniz: stackoverflow.com/questions/45577301/… .
Victor

1
@vic sorun değil ve bir asker olarak önceki kötü deneyiminiz için özür dilerim. Sadece yorumlar, sorular ve cevaplar için uygun değildir.
VonC

34

interface{}kendi özel türünüz de dahil olmak üzere her türden değer koyabileceğiniz anlamına gelir. Go'daki tüm türler boş bir arabirim sağlar ( interface{}boş bir arabirimdir).
Örneğinizde, Mesaj alanı herhangi bir türde değere sahip olabilir.

Misal:

package main

import (
    "fmt"
)

type Body struct {
    Msg interface{}
}

func main() {
    b := Body{}
    b.Msg = "5"
    fmt.Printf("%#v %T \n", b.Msg, b.Msg) // Output: "5" string
    b.Msg = 5

    fmt.Printf("%#v %T", b.Msg, b.Msg) //Output:  5 int
}

Oyun Alanına Git


12

Buna boş arayüz denir ve her tür tarafından uygulanır, yani Msgalana her şeyi koyabilirsiniz .

Misal :

body := Body{3}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:3}

body = Body{"anything"}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:"anything"}

body = Body{body}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:main.Body{Msg:"anything"}}

Bu, bir türün, arabirimin tüm yöntemlerine sahip olur olmaz bir arabirimi uyguladığı gerçeğinin mantıksal uzantısıdır.


kullanıcı tanımlı bir yapıya int olabileceği anlamına gelir ??
kullanıcı

11

Burada zaten iyi cevaplar var. Bunu sezgisel olarak anlamak isteyenler için de kendiminkini ekleyeyim:


Arayüz

İşte tek yöntemli bir arayüz:

type Runner interface {
    Run()
}

Dolayısıyla, bir Run()yöntemi olan herhangi bir tür , Runner arayüzünü karşılar:

type Program struct {
    /* fields */
}

func (p Program) Run() {
    /* running */
}

func (p Program) Stop() {
    /* stopping */
}
  • Program türünün ayrıca bir Durdurma yöntemi olmasına rağmen, yine de Runner arabirimini karşılar çünkü gereken tek şey, onu tatmin etmek için bir arabirimin tüm yöntemlerine sahip olmaktır.

  • Yani, bir Run metoduna sahip ve Runner arayüzünü tatmin ediyor.


Boş Arayüz

Herhangi bir yöntem içermeyen adlandırılmış boş bir arabirim:

type Empty interface {
    /* it has no methods */
}

Yani her tür bu arayüzü karşılar. Çünkü bu arayüzü sağlamak için hiçbir yönteme ihtiyaç yoktur. Örneğin:

// Because, Empty interface has no methods, following types satisfy the Empty interface
var a Empty

a = 5
a = 6.5
a = "hello"

Ancak yukarıdaki Program türü bunu karşılıyor mu? Evet:

a = Program{} // ok

arayüz {}, yukarıdaki Boş arayüze eşittir.

var b interface{}

// true: a == b

b = a
b = 9
b = "bye"

Gördüğünüz gibi, gizemli bir yanı yok ama kötüye kullanılması çok kolay. Olabildiğince ondan uzak dur.


https://play.golang.org/p/A-vwTddWJ7G


type Runner interfaceGit oyun alanı örneğinde kullanılmayan olduğunu.
Tom J

9

Gönderen Golang Özellikler :

Bir arabirim türü, arabirimi adı verilen bir yöntem kümesini belirtir. Arabirim türünün bir değişkeni, arabirimin herhangi bir üst kümesi olan bir yöntem kümesiyle her türden bir değeri depolayabilir. Böyle bir tipin arayüzü uyguladığı söylenir. Arabirim türünde başlatılmamış bir değişkenin değeri sıfırdır.

Bir tür, yöntemlerinin herhangi bir alt kümesini içeren herhangi bir arabirimi uygular ve bu nedenle birkaç farklı arabirim uygulayabilir. Örneğin, tüm türler boş arabirimi uygular:

arayüz{}

Graps kavramları:

  1. Her şeyin bir Tipi vardır . Sen şimdi T. edelim diyelim diyelim, yeni bir tür tanımlayabilirsiniz bizim Tip T3 yöntemleri vardır: A, B, C.
  2. Bir tür için belirtilen yöntemler kümesine " arabirim türü " denir . Örneğimizde bunu diyelim: T_interface. EşittirT_interface = (A, B, C)
  3. Yöntemlerin imzasını tanımlayarak bir "arayüz türü" oluşturabilirsiniz .MyInterface = (A, )
  4. Bir belirtirken değişkeni arasında tip , "arabirim türü", ona da arayüzünün bir üst kümesidir bir arayüze sahip yalnızca türlerini atayabilirsiniz. Tüm yöntemler içinde bulunan o Bunun anlamı MyInterfaceiçini kontrol edilmeliT_interface

Tüm tiplerin tüm "arayüz tiplerinin" boş arayüzün bir üst kümesi olduğu sonucuna varabilirsiniz.


1

@VonC'nin mükemmel cevabını ve @ NickCraig-Wood'un yorumunu genişleten bir örnek. interface{}herhangi bir şeye işaret edebilir ve onu kullanmak için bir cast / type iddiasına ihtiyacınız vardır.

package main

import (
    . "fmt"
    "strconv"
)

var c = cat("Fish")
var d = dog("Bone")

func main() {
    var i interface{} = c
    switch i.(type) {
    case cat:
        c.Eat() // Fish
    }

    i = d
    switch i.(type) {
    case dog:
        d.Eat() // Bone
    }

    i = "4.3"
    Printf("%T %v\n", i, i) // string 4.3
    s, _ := i.(string)      // type assertion
    f, _ := strconv.ParseFloat(s, 64)
    n := int(f)             // type conversion
    Printf("%T %v\n", n, n) // int 4
}

type cat string
type dog string
func (c cat) Eat() { Println(c) }
func (d dog) Eat() { Println(d) }

ideğeri olan boş bir arayüzün değişkenidir cat("Fish"). Arayüz tipinin bir değerinden bir metot değeri yaratmak yasaldır. Bkz. Https://golang.org/ref/spec#Interface_types .

Bir tip anahtarı, iarayüz tipinin olduğunu doğrular cat("Fish"). Bkz. Https://golang.org/doc/effective_go.html#type_switch . idaha sonra yeniden atanır dog("Bone"). Bir tip anahtarı, iarayüz tipinin olarak değiştiğini doğrular dog("Bone").

Ayrıca derleyiciden türünün olup olmadığını kontrol etmesini isteyebilirsiniz. T arabirimini uygulayan Ibir ödevi çalışarak: var _ I = T{}. Https://golang.org/doc/faq#guarantee_satisfies_interface ve https://stackoverflow.com/a/60663003/12817546 sayfalarına bakın .

Tüm türler boş arabirimi uygular interface{}. Bkz. Https://talks.golang.org/2012/goforc.slide#44 ve https://golang.org/ref/spec#Interface_types . Bu örnekte, ibu sefer bir "4.3" dizesine yeniden atanmıştır. idaha sonra yeni bir dize değişkenine atanır sile i.(string)öncesf kullanılarak float64 türüne dönüştürülür strconv. Son olarak f, n4'e eşit bir int türüne dönüştürülür . Bkz. Tür dönüştürme ve tür onaylama arasındaki fark nedir?

Go'nun yerleşik haritaları ve dilimlerinin yanı sıra, kapları oluşturmak için boş arabirimi kullanma (açık kutudan çıkarma ile) yeteneği, çoğu durumda jeneriklerin daha az sorunsuz olsa da etkinleştireceği şeyi yapan kod yazmanın mümkün olduğu anlamına gelir. Bkz. Https://golang.org/doc/faq#generics .


Kodu bir arayüzle ayırın. Stackoverflow.com/a/62297796/12817546 adresine bakın . Bir yöntemi "dinamik olarak" çağırın. Stackoverflow.com/a/62336440/12817546 adresine bakın . Bir Go paketine erişin. Stackoverflow.com/a/62278078/12817546 adresine bakın . Bir değişkene herhangi bir değer atayın. Stackoverflow.com/a/62337836/12817546 adresine bakın .
Tom J
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.