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{}
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
[[26]}początkujący susły są skłonni wierzyć, że "DoSomething
, jaki jest typv
?v
jest dowolnego rodzaju" , ale to jest złe.v
nie jest żadnego typu; jest typuinterface{}
.Podczas przekazywania wartości do funkcji
DoSomething
, runtime Go wykona konwersję typu (jeśli to konieczne) i skonwertuje wartość nainterface{}
wartość.
Wszystkie wartości mają dokładnie jeden typ w czasie wykonywania, A Typ statycznyv
tointerface{}
.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.
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 forStringer
holding type Binary wymienia metody używane do zaspokojenia Stringera, co jest po prostuString
: Inne metody binarne (Get
) nie pojawiają się witable
.Drugi wyraz w wartości interfejsu wskazuje na rzeczywiste dane , w tym przypadku kopię
b
.
Zadanievar s Stringer = b
tworzy kopięb
zamiast wskazywać nab
z tego samego powodu, dla któregovar c uint64 = b
tworzy kopię: jeślib
później się zmieni,s
ic
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.
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
}
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.
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.
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
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:
- Wszystko ma typ . Możesz zdefiniować nowy typ, nazwijmy go T. powiedzmy, że nasz typ
T
mA 3 metody:A
,B
,C
. - 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)
- można utworzyć "Typ interfejsu" przez definiowanie sygnatury metod.
MyInterface = (A, )
- 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 wT_interface
Można wywnioskować, że wszystkie "typy interfejsów" wszystkich typów są supersetem pustego interfejsu.
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 .
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