Możesz zapoznać się z artykułem „ Jak korzystać z interfejsów w Go ” (na podstawie „ opisu interfejsów Russa Coxa ”):
Co to jest interfejs?
Interfejs to dwie rzeczy:
- to zbiór metod,
- ale to też jest typ
interface{}
Litery tym pusta interfejs jest interfejsem, który nie ma żadnych metod.
Ponieważ nie ma słowa kluczowego implements, wszystkie typy implementują co najmniej zero metod, a spełnienie interfejsu jest wykonywane automatycznie, wszystkie typy spełniają pusty interfejs .
Oznacza to, że jeśli napiszesz funkcję, która przyjmuje interface{}
wartość jako parametr, możesz nadać tej funkcji dowolną wartość .
(Oto, co Msg
reprezentuje twoje pytanie: dowolna wartość)
func DoSomething(v interface{}) {
}
Oto, gdzie robi się mylące:
wewnątrz DoSomething
funkcji, jaki jest v
jej typ?
Początkującym susłom prowadzi się przekonanie, że „ v
są dowolnego typu”, ale to jest złe.
v
nie jest żadnego rodzaju; to jest interface{}
typowe .
Podczas przekazywania wartości do DoSomething
funkcji środowisko wykonawcze Go wykona konwersję typu (w razie potrzeby) i przekonwertuje wartość na interface{}
wartość .
Wszystkie wartości mają dokładnie jeden typ w czasie wykonywania, a v
jeden typ statyczny to interface{}
.
Wartość interfejsu składa się z dwóch słów danych :
- jedno słowo jest używane do wskazania tabeli metod dla typu bazowego wartości,
- a drugie słowo jest używane do wskazania rzeczywistych danych przechowywanych przez tę wartość.
Dodatek: Oto artykuł Russa 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źnik 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ą interfejsów lub itable (wymawiane i-table; w źródłach środowiska uruchomieniowego nazwa implementacji C to Itab).
Część itable zaczyna się od pewnych metadanych dotyczących typów, a następnie staje się listą wskaźników funkcji.
Zauważ, że itable odpowiada typowi interfejsu, a nie typowi dynamicznemu .
Jeśli chodzi o nasz przykład, opcja Stringer
przechowywania typu Binary zawiera listę metod używanych do zaspokojenia Stringer, czyli po prostu String
: Inne metody Binary ( Get
) nie pojawiają się w itable
.
Drugie słowo w wartości interfejsu wskazuje na rzeczywiste dane , w tym przypadku kopię b
.
Przypisanie var s Stringer = b
tworzy kopię b
zamiast wskazywać na b
z tego samego powodu, który var c uint64 = b
tworzy kopię: jeśli b
później ulegnie zmianie s
i c
przypuszczalnie ma mieć oryginalną wartość, a nie nową.
Wartości przechowywane w interfejsach mogą być dowolnie duże, ale tylko jedno słowo jest przeznaczone do przechowywania wartości w strukturze interfejsu, więc przypisanie przydziela porcję pamięci na stercie i zapisuje wskaźnik w gnieździe jednowyrazowym.
interface{}
jest mniej więcej odpowiednikiemvoid *
w C. Może wskazywać na wszystko i potrzebujesz asercji rzutowania / typu, aby go użyć.