Co oznacza interfejs{}?

Jestem nowy w interfejsach i próbuję wykonać żądanie SOAP przez github

Nie rozumiem znaczenia

Msg interface{}

W tym kodzie:

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

type Body struct {
    Msg interface{}
}

Obserwowałem tę samą składnię w

fmt.Println

Ale nie rozumiem, co jest osiągane przez

interface{}
 144
go
Author: Flimzy, 2014-04-18

6 answers

Możesz odnieść się do artykułu " Jak korzystać z interfejsów w Go "(na podstawie " Opis interfejsów"):

Czym jest interfejs?

Interfejs to dwie rzeczy:

    Jest to zbiór metod,
  • ale jest to również Typ

The interface{} Typ, empty interface jest interfejsem, który nie posiada metod.

Ponieważ nie ma żadnych narzędzi słowo kluczowe, Wszystkie typy implementują co najmniej zerowe metody, a spełnianie interfejsu odbywa się automatycznie, wszystkie typy spełniają pusty interfejs .
Oznacza to, że jeśli piszesz funkcję, która przyjmuje wartość {[2] } jako parametr, możesz podać tę funkcję z dowolną wartością .

(To właśnie Msg reprezentuje w twoim pytaniu: dowolna wartość)

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

Tutaj robi się mylące:

Wewnątrz funkcji DoSomething, jaki jest typ v?

[[26]}początkujący susły są skłonni wierzyć, że "v jest dowolnego rodzaju" , ale to jest złe.
v nie jest żadnego typu; jest typu interface{} .

Podczas przekazywania wartości do funkcji DoSomething, runtime Go wykona konwersję typu (jeśli to konieczne) i skonwertuje wartość na interface{} wartość.
Wszystkie wartości mają dokładnie jeden typ w czasie wykonywania, A Typ statyczny v to interface{}.

Wartość interfejsu jest zbudowana z dwóch słów danych :

  • jedno słowo jest używane do wskazywania tabeli metod dla bazowego typu wartości,
  • i inne słowo jest używane, aby wskazać rzeczywiste dane są przechowywane przez tę wartość.

Dodatek: jest to artykuł were Russ jest dość kompletny, dotyczący struktury interfejsu:

type Stringer interface {
    String() string
}

Wartości interfejsu są reprezentowane jako para dwóch słów dająca wskaźnik do informacji o typie przechowywanym w interfejsie oraz wskaźnika do powiązanych danych.
Przypisanie b do wartości interfejsu typu Stringer ustawia oba słowa wartości interfejsu.

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

Pierwsze słowo w wartości interfejsu wskazuje na to, co nazywam tabelą interfejsu lub itable (wymawiane i-table; w źródłach runtime nazwa implementacji C to Itab).
Itable zaczyna się od niektórych metadanych dotyczących typów i następnie staje się listą wskaźników funkcji.
zauważ, że itable odpowiada typowi interfejsu, a nie typowi dynamicznemu .
W naszym przykładzie, itable for Stringer holding type Binary wymienia metody używane do zaspokojenia Stringera, co jest po prostu String: Inne metody binarne (Get) nie pojawiają się w itable.

Drugi wyraz w wartości interfejsu wskazuje na rzeczywiste dane , w tym przypadku kopię b.
Zadanie var s Stringer = b tworzy kopię b zamiast wskazywać na b z tego samego powodu, dla którego var c uint64 = b tworzy kopię: jeśli b później się zmieni, s i c powinny mieć oryginalną wartość, a nie nową.
Wartości przechowywane w interfejsach mogą być dowolnie duże, ale tylko jedno słowo jest dedykowane do przechowywania wartości w strukturze interfejsu, więc przypisanie przydziela kawałek pamięci na stercie i rejestruje wskaźnik w jednowyrazowym slocie.

 198
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-19 05:47:31

interface{} oznacza, że możesz umieścić wartość dowolnego typu, w tym własnego typu niestandardowego. Wszystkie typy W Go spełniają pusty Interfejs (interface{} jest pustym interfejsem).
W twoim przykładzie pole Msg może mieć wartość dowolnego typu.

Przykład:

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
}

Go Playground

 35
Author: Minty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-13 04:58:22

Nazywa się empty interface i jest zaimplementowany przez wszystkie typy, co oznacza, że możesz umieścić cokolwiek w polu Msg.

Przykład:

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

Jest to logiczne rozszerzenie faktu, że typ implementuje interfejs tak szybko, jak ma wszystkie metody interfejsu.

 13
Author: Denys Séguret,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-18 06:49:47

Są już dobre odpowiedzi tutaj. Dodam też własne dla innych, którzy chcą to intuicyjnie zrozumieć:


Interfejs

Oto interfejs z jedną metodą:

type Runner interface {
    Run()
}

Więc każdy typ, który ma metodę Run() spełnia interfejs Runnera:

type Program struct {
    /* fields */
}

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

func (p Program) Stop() {
    /* stopping */
}
  • Chociaż typ programu ma również metodę Stop, nadal spełnia interfejs Runner, ponieważ wszystko, co jest potrzebne, to mieć wszystkie metody interfejsu aby go zaspokoić.

  • Ma więc metodę Run i spełnia interfejs Runnera.


Pusty Interfejs

Oto nazwany pusty interfejs bez żadnych metod:

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

Więc każdy typ spełnia ten interfejs. Ponieważ nie jest potrzebna żadna metoda, aby spełnić ten interfejs. Na przykład:

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

a = 5
a = 6.5
a = "hello"

Ale czy program typu powyżej go zaspokaja? Tak:

a = Program{} // ok

Interface {} jest równy pustemu interfejs powyżej.

var b interface{}

// true: a == b

b = a
b = 9
b = "bye"
Jak widzisz, nie ma w tym nic tajemniczego, ale łatwo go nadużywać. Trzymaj się od tego z daleka.

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

 11
Author: inanc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-11 19:47:03

Z :

Typ interfejsu określa zestaw metod zwany jego interfejsem. A zmienna typu interface może przechowywać wartość dowolnego typu za pomocą metody set to dowolny superset interfejsu. O takim typie mówi się zaimplementuj interfejs. Wartość niezainicjowanej zmiennej o Typ interfejsu to zero.

Typ implementuje dowolny interfejs zawierający dowolny podzbiór swoich metod i może w związku z tym zaimplementować kilka odrębnych interfejsów. Na przykład, wszystkie typy implementują pusty interfejs:

Interfejs {}

Pojęcia do grapów to:

  1. Wszystko ma typ . Możesz zdefiniować nowy typ, nazwijmy go T. powiedzmy, że nasz typ T mA 3 metody: A, B, C.
  2. zbiór metod określonych dla typu nazywa się " Typ interfejsu ". Nazwijmy to w naszym przykładzie: T_interface. Jest równe T_interface = (A, B, C)
  3. można utworzyć "Typ interfejsu" przez definiowanie sygnatury metod. MyInterface = (A, )
  4. kiedy podasz zmienną typu , "Typ interfejsu", możesz przypisać do niej tylko typy, które mają interfejs, który jest supersetem twojego interfejsu. Oznacza to, że wszystkie metody zawarte w MyInterface muszą być zawarte w T_interface

Można wywnioskować, że wszystkie "typy interfejsów" wszystkich typów są supersetem pustego interfejsu.

 9
Author: fabrizioM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Przykład, który rozszerza doskonałą odpowiedź przez @VonC i komentarz przez @NickCraig-Wood. interface{} może wskazywać na wszystko i potrzebujesz twierdzenia cast/type, aby go użyć.

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

i jest zmienną pustego interfejsu o wartości cat("Fish"). Legalne jest tworzenie wartości metody z wartości typu interface. Zobacz https://golang.org/ref/spec#Interface_types .

Przełącznik typu potwierdza i Typ interfejsu to cat("Fish"). Zobacz też https://golang.org/doc/effective_go.html#type_switch. i jest następnie przypisany do dog("Bone"). Przełącznik typu potwierdza, że typ interfejsu i zmienił się na dog("Bone").

Możesz również poprosić kompilator o sprawdzenie, czy typ T implementuje interfejs I, wykonując zadanie: var _ I = T{}. Zobacz https://golang.org/doc/faq#guarantee_satisfies_interface i https://stackoverflow.com/a/60663003/12817546 .

Wszystkie typy implementują puste Interfejs interface{}. Zobacz https://talks.golang.org/2012/goforc.slide#44 i https://golang.org/ref/spec#Interface_types . W tym przykładzie i jest ponownie przypisany, tym razem do ciągu znaków "4.3".i jest następnie przypisany do nowej zmiennej łańcuchowej s z i.(string), zanim s zostanie przekonwertowana do typu float64 f za pomocą strconv. Ostatecznie f jest konwertowane do n typu int równego 4. Zobacz Jaka jest różnica między konwersją typu A typem twierdzenie?

Wbudowane mapy i plasterki Go oraz możliwość używania pustego interfejsu do konstruowania kontenerów (z wyraźnym unboxingiem) oznaczają, że w wielu przypadkach możliwe jest pisanie kodu, który robi to, co umożliwiłyby generyki, o ile mniej płynnie. Zobacz https://golang.org/doc/faq#generics .

 1
Author: Tom L,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-12 05:04:27