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{}
}
Zauważyłem tę samą składnię w
fmt.Println
ale nie rozumiem, przez co się osiąga
interface{}
interface{}
jest mniej więcej odpowiednikiemvoid *
w C. Może wskazywać na wszystko i potrzebujesz asercji rzutowania / typu, aby go użyć.Odpowiedzi:
Możesz zapoznać się z artykułem „ Jak korzystać z interfejsów w Go ” (na podstawie „ opisu interfejsów Russa Coxa ”):
(Oto, co
Msg
reprezentuje twoje pytanie: dowolna wartość)func DoSomething(v interface{}) { // ... }
Dodatek: Oto artykuł Russa dotyczący struktury interfejsu:
type Stringer interface { String() string }
źródło
interface{}
oznacza, że możesz podać wartość dowolnego typu, w tym własny typ niestandardowy. Wszystkie typy w Go spełniają wymagania pustego interfejsu (interface{}
jest to pusty interfejs).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 }
Idź na plac zabaw
źródło
Nazywa się to pustym interfejsem i jest implementowane przez wszystkie typy, co oznacza, że możesz umieścić wszystko w
Msg
polu.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, gdy tylko ma wszystkie metody interfejsu.
źródło
Tutaj są już dobre odpowiedzi. Dodam też własne dla innych, którzy chcą to zrozumieć intuicyjnie:
Berło
Oto interfejs z jedną metodą:
type Runner interface { Run() }
Zatem każdy typ, który ma
Run()
metodę, spełnia interfejs Runnera:type Program struct { /* fields */ } func (p Program) Run() { /* running */ } func (p Program) Stop() { /* stopping */ }
Chociaż typ Program ma również metodę Stop, nadal spełnia on interfejs Runnera, ponieważ wszystko, czego potrzeba, to mieć wszystkie metody interfejsu, aby go spełnić.
Tak więc ma metodę Run i spełnia interfejs Runner.
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ć wymagania tego interfejsu. 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 powyższy typ programu to spełnia? Tak:
a = Program{} // ok
interfejs {} jest równy powyższemu pustemu interfejsowi.
var b interface{} // true: a == b b = a b = 9 b = "bye"
Jak widzisz, nie ma w tym nic tajemniczego, ale bardzo łatwo jest go nadużyć. Trzymaj się od tego z daleka, jak tylko możesz.
https://play.golang.org/p/A-vwTddWJ7G
źródło
type Runner interface
jest używany w przykładzie placu zabaw Go.Ze specyfikacji Golang :
Koncepcje grapsów to:
T
posiada 3 metody:A
,B
,C
.T_interface = (A, B, C)
MyInterface = (A, )
MyInterface
muszą być zawarte w środkuT_interface
Możesz wywnioskować, że wszystkie „typy interfejsów” wszystkich typów stanowią nadzbiór pustego interfejsu.
źródło
Przykład, który rozszerza doskonałą odpowiedź @VonC i komentarz @ NickCraig-Wood.
interface{}
może wskazywać na cokolwiek i potrzebujesz asercji rzutowania / typu, 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 z wartościącat("Fish")
. Tworzenie wartości metody z wartości typu interfejsu jest dozwolone. Zobacz https://golang.org/ref/spec#Interface_types .Przełącznik typu potwierdza
i
, że typ interfejsu tocat("Fish")
. Zobacz https://golang.org/doc/effective_go.html#type_switch .i
jest następnie przypisywany dodog("Bone")
. Przełącznik typu potwierdza, żei
typ interfejsu zmienił się nadog("Bone")
.Można również poprosić kompilator, by sprawdzić, czy typ
T
implementuje interfejsI
próbując zadanie:var _ I = T{}
. Zobacz https://golang.org/doc/faq#guarantee_satisfies_interface i https://stackoverflow.com/a/60663003/12817546 .Wszystkie typy implementują pusty interfejs
interface{}
. Zobacz https://talks.golang.org/2012/goforc.slide#44 i https://golang.org/ref/spec#Interface_types . W tym przykładziei
zostanie ponownie przypisany, tym razem do łańcucha „4.3”.i
jest następnie przypisywany do nowej zmiennej łańcuchowej,s
z którąi.(string)
przeds
jest konwertowana na typ float64f
przy użyciustrconv
. Ostatecznief
jest konwertowany nan
typ int równy 4. Zobacz Jaka jest różnica między konwersją typu a potwierdzeniem typu?Wbudowane mapy i wycinki w Go, a także możliwość używania pustego interfejsu do konstruowania kontenerów (z jawnym rozpakowywaniem) oznaczają, że w wielu przypadkach można napisać kod, który robi to, co generyczne umożliwiłyby, jeśli jest mniej płynne. Zobacz https://golang.org/doc/faq#generics .
źródło