Apa arti dari antarmuka {}?

133

Saya baru mengenal antarmuka dan mencoba melakukan permintaan SOAP oleh github

Saya tidak mengerti artinya

Msg interface{}

dalam kode ini:

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

type Body struct {
    Msg interface{}
}

Saya telah mengamati sintaks yang sama di

fmt.Println

tetapi tidak mengerti apa yang sedang dicapai

interface{}
pengguna
sumber
20
interface{}kurang lebih sama dengan void *di C. Itu bisa menunjuk ke apa pun dan Anda membutuhkan pernyataan cor / tipe untuk menggunakannya.
Nick Craig-Wood
Apa arti dari antarmuka {}? Lihat stackoverflow.com/a/62337836/12817546 .
Tom J

Jawaban:

189

Anda dapat merujuk ke artikel " Cara menggunakan antarmuka di Go " (berdasarkan " deskripsi antarmuka Cox "):

Apa itu antarmuka?

Antarmuka adalah dua hal:

  • itu adalah seperangkat metode,
  • tetapi juga tipe

The interface{}jenis, antarmuka kosong adalah antarmuka yang tidak memiliki metode.

Karena tidak ada kata kunci implement, semua jenis menerapkan setidaknya metode nol, dan memuaskan antarmuka dilakukan secara otomatis, semua jenis memenuhi antarmuka kosong .
Itu berarti bahwa jika Anda menulis fungsi yang mengambil interface{}nilai sebagai parameter, Anda bisa menyediakan fungsi itu dengan nilai apa pun .

(Itulah yang Msgdiwakili dalam pertanyaan Anda: nilai apa pun)

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

Di sinilah membingungkan:

di dalam DoSomethingfungsi, apa vtipe?

Para pemula akan dituntun untuk percaya bahwa " vadalah dari jenis apa pun", tetapi itu salah.
vbukan jenis apa pun; itu interface{}tipe .

Saat meneruskan nilai ke dalam DoSomethingfungsi, Go runtime akan melakukan konversi tipe (jika perlu), dan mengonversi nilai menjadi interface{}nilai .
Semua nilai memiliki tepat satu jenis saat runtime, dan vsatu jenis statis adalah interface{}.

Nilai antarmuka dibangun dari dua kata data :

  • satu kata digunakan untuk menunjuk ke tabel metode untuk tipe yang mendasari nilai,
  • dan kata lain digunakan untuk menunjukkan data aktual yang dipegang oleh nilai tersebut.

Tambahan: Ini adalah artikel Russ yang cukup lengkap mengenai struktur antarmuka:

type Stringer interface {
    String() string
}

Nilai antarmuka direpresentasikan sebagai pasangan dua kata yang memberikan penunjuk ke informasi tentang tipe yang disimpan dalam antarmuka dan penunjuk ke data terkait.
Menetapkan b ke nilai antarmuka dari tipe Stringer menetapkan kedua kata dari nilai antarmuka.

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

Kata pertama dalam nilai antarmuka menunjuk pada apa yang saya sebut sebagai tabel antarmuka atau dapat diubah (diucapkan i-table; dalam sumber runtime, nama implementasi C adalah Itab).
Itable dimulai dengan beberapa metadata tentang tipe yang terlibat dan kemudian menjadi daftar fungsi pointer.
Perhatikan bahwa itable sesuai dengan jenis antarmuka, bukan tipe dinamis .
Dalam hal contoh kami, itable untuk Stringermemegang tipe Binary mencantumkan metode yang digunakan untuk memuaskan Stringer, yaitu String: Metode Binary lainnya ( Get) tidak membuat tampilan di itable.

Kata kedua dalam nilai antarmuka menunjukkan data aktual , dalam hal ini salinan b.
Tugas var s Stringer = bmembuat salinan bdaripada titik pada buntuk alasan yang sama yang var c uint64 = bmembuat salinan: jika bnanti berubah, sdan cseharusnya memiliki nilai asli, bukan yang baru.
Nilai yang disimpan dalam antarmuka mungkin besar secara sewenang-wenang, tetapi hanya satu kata yang didedikasikan untuk memegang nilai dalam struktur antarmuka, sehingga tugas tersebut mengalokasikan sejumlah memori pada heap dan mencatat pointer di slot satu kata.

VONC
sumber
4
Apa yang Anda maksud dengan "dua kata data"? Secara khusus, apa arti "kata" itu?
Mingyu
3
@Mingyu Saya telah menyelesaikan jawaban untuk menggambarkan dua kata (poin 32-bit).
VonC
2
@Mingyu: VonC merujuk pada sebuah kata dalam pengertian arsitektur komputer - kumpulan bit yang menentukan sepotong data ukuran tetap. Ukuran kata diatur oleh arsitektur prosesor yang Anda gunakan.
Dan Esparza
1
terima kasih @VonC untuk balasan Anda ... yang benar adalah bahwa saya lelah mendapatkan downpost ketika saya bertanya hal-hal .. orang-orang sebagian besar waktu memberitahu saya bahwa saya harus membaca dokumen ... saya akan mengingat saran Anda jika saya merasa dengan akan benar menulis posting untuk itu ... tetapi saya benar-benar tidak bisa memikirkan cara lain untuk bertanya. Jadi terima kasih dan maafkan keinginan rendah saya. Anda dipersilakan untuk melihat ini: stackoverflow.com/questions/45577301/... untuk mengklarifikasi mengapa saya tidak suka bertanya.
Victor
1
@vic tidak ada masalah, dan maaf untuk pengalaman buruk Anda sebelumnya sebagai penanya. Hanya saja komentar tidak cocok untuk pertanyaan dan jawaban.
VonC
34

interface{}berarti Anda dapat memberi nilai pada jenis apa pun, termasuk jenis khusus Anda sendiri. Semua tipe di Go memenuhi antarmuka kosong ( interface{}adalah antarmuka kosong).
Dalam contoh Anda, bidang Msg dapat memiliki nilai jenis apa pun.

Contoh:

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
}

Pergi Bermain

Minty
sumber
12

Ini disebut antarmuka kosong dan diimplementasikan oleh semua jenis, yang berarti Anda dapat meletakkan apa pun di Msglapangan.

Contoh:

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"}}

Ini adalah ekstensi logis dari fakta bahwa suatu jenis mengimplementasikan antarmuka segera setelah ia memiliki semua metode antarmuka.

Denys Séguret
sumber
berarti itu bisa menjadi int untuk struktur yang ditetapkan pengguna ??
pengguna
11

Sudah ada jawaban bagus di sini. Izinkan saya menambahkan milik saya juga untuk orang lain yang ingin memahaminya secara intuitif:


Antarmuka

Berikut ini antarmuka dengan satu metode:

type Runner interface {
    Run()
}

Jadi tipe apa pun yang memiliki Run()metode memenuhi antarmuka Runner:

type Program struct {
    /* fields */
}

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

func (p Program) Stop() {
    /* stopping */
}
  • Meskipun tipe Program juga memiliki metode Stop, masih memenuhi antarmuka Runner karena semua yang diperlukan adalah memiliki semua metode antarmuka untuk memuaskannya.

  • Jadi, ia memiliki metode Jalankan dan memenuhi antarmuka Runner.


Antarmuka Kosong

Inilah antarmuka kosong bernama tanpa metode apa pun:

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

Jadi jenis apa pun memenuhi antarmuka ini. Karena, tidak diperlukan metode untuk memuaskan antarmuka ini. Sebagai contoh:

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

a = 5
a = 6.5
a = "hello"

Tetapi, apakah tipe Program di atas memuaskan? Iya:

a = Program{} // ok

antarmuka {} sama dengan antarmuka Kosong di atas.

var b interface{}

// true: a == b

b = a
b = 9
b = "bye"

Seperti yang Anda lihat, tidak ada yang misterius tentang itu tetapi sangat mudah disalahgunakan. Jauhi itu sebanyak yang Anda bisa.


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

Inanc Gumus
sumber
Ini type Runner interfacetidak digunakan dalam contoh taman bermain Go.
Tom J
9

Dari Spesifikasi Golang :

Tipe antarmuka menentukan metode yang disebut antarmuka. Variabel tipe antarmuka dapat menyimpan nilai jenis apa pun dengan set metode yang merupakan superset dari antarmuka. Jenis seperti itu dikatakan mengimplementasikan antarmuka. Nilai variabel antarmuka tipe yang tidak diinisialisasi adalah nol.

Suatu tipe mengimplementasikan antarmuka apa pun yang terdiri dari himpunan bagian dari metodenya dan karenanya dapat mengimplementasikan beberapa antarmuka berbeda. Misalnya, semua jenis menerapkan antarmuka kosong:

antarmuka {}

Konsep yang harus dihadapi adalah:

  1. Semuanya memiliki Tipe . Anda dapat menentukan jenis baru, sebut saja T. Mari katakanlah sekarang Jenis kami Tmemiliki 3 metode: A, B, C.
  2. Himpunan metode yang ditentukan untuk suatu tipe disebut " tipe antarmuka ". Sebut saja dalam contoh kita: T_interface. Adalah sama denganT_interface = (A, B, C)
  3. Anda dapat membuat "tipe antarmuka" dengan mendefinisikan tanda tangan metode.MyInterface = (A, )
  4. Ketika Anda menentukan variabel dari tipe , "jenis antarmuka", Anda dapat menetapkan untuk hanya jenis yang memiliki antarmuka yang merupakan superset dari antarmuka Anda. Itu berarti bahwa semua metode yang terkandung di MyInterfacedalamnya harus terkandung di dalamnyaT_interface

Anda dapat menyimpulkan bahwa semua "tipe antarmuka" dari semua jenis adalah superset dari antarmuka kosong.

fabrizioM
sumber
1

Contoh yang memperluas jawaban yang sangat baik oleh @VonC dan komentar oleh @ NickCraig-Wood. interface{}dapat menunjuk ke apa saja dan Anda memerlukan pernyataan cor / type untuk menggunakannya.

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) }

iadalah variabel antarmuka kosong dengan nilai cat("Fish"). Adalah sah untuk membuat nilai metode dari nilai tipe antarmuka. Lihat https://golang.org/ref/spec#Interface_types .

Saklar tipe mengkonfirmasi itipe antarmuka cat("Fish"). Lihat https://golang.org/doc/effective_go.html#type_switch . ikemudian dipindahkan ke dog("Bone"). Switch tipe mengkonfirmasi bahwa itipe antarmuka telah berubah menjadi dog("Bone").

Anda juga dapat meminta compiler untuk memeriksa bahwa jenis Tmengimplementasikan antarmuka Idengan mencoba tugas: var _ I = T{}. Lihat https://golang.org/doc/faq#guarantee_satisfies_interface dan https://stackoverflow.com/a/60663003/12817546 .

Semua tipe mengimplementasikan antarmuka kosong interface{}. Lihat https://talks.golang.org/2012/goforc.slide#44 dan https://golang.org/ref/spec#Interface_types . Dalam contoh ini, idipindahkan, kali ini ke string "4.3". ikemudian ditugaskan ke variabel string baru sdengan i.(string)sebelum sdikonversi ke tipe float64 fmenggunakan strconv. Akhirnya fdikonversi ke ntipe int sama dengan 4. Lihat Apa perbedaan antara konversi tipe dan penegasan tipe?

Peta dan irisan bawaan Go, ditambah kemampuan untuk menggunakan antarmuka kosong untuk membuat wadah (dengan unboxing eksplisit) berarti dalam banyak kasus, dimungkinkan untuk menulis kode yang melakukan apa yang dimungkinkan oleh obat generik, jika kurang lancar. Lihat https://golang.org/doc/faq#generics .

Tom J
sumber
Pisahkan kode dengan antarmuka. Lihat stackoverflow.com/a/62297796/12817546 . Panggil metode "dinamis". Lihat stackoverflow.com/a/62336440/12817546 . Akses paket Go. Lihat stackoverflow.com/a/62278078/12817546 . Tetapkan nilai apa pun untuk variabel. Lihat stackoverflow.com/a/62337836/12817546 .
Tom J