Jestem ciekaw dlaczego Go does't niejawnie przekonwertować []T
do []interface{}
kiedy będzie niejawnie konwertować T
do interface{}
. Czy w tej konwersji brakuje czegoś nietrywialnego?
Przykład:
func foo([]interface{}) { /* do something */ }
func main() {
var a []string = []string{"hello", "world"}
foo(a)
}
go build
narzeka
nie można użyć (typu [] ciągu) jako interfejsu typu [] {} w argumencie funkcji
A jeśli spróbuję to zrobić wyraźnie, to samo: b := []interface{}(a)
narzeka
nie można przekonwertować ciągu (typ []) na interfejs typu [] {}
Więc za każdym razem, gdy muszę wykonać tę konwersję (która wydaje się często pojawiać), robiłem coś takiego:
b = make([]interface{}, len(a), len(a))
for i := range a {
b[i] = a[i]
}
Czy jest lepszy sposób, aby to zrobić, lub standardowe funkcje biblioteki, aby pomóc w tych konwersjach? Głupio wydaje się pisać 4 dodatkowe wiersze kodu za każdym razem, gdy chcę wywołać funkcję, która może przyjąć listę np. Ints lub łańcuchów.
źródło
Odpowiedzi:
W Go obowiązuje ogólna zasada, że składnia nie powinna ukrywać skomplikowanych / kosztownych operacji. Konwersja a
string
na aninterface{}
odbywa się w czasie O (1). Konwersja a[]string
na aninterface{}
odbywa się również w czasie O (1), ponieważ plasterek jest nadal jedną wartością. Jednak konwersja a[]string
na an[]interface{}
to czas O (n), ponieważ każdy element wycinka musi zostać przekonwertowany na aninterface{}
.Jedynym wyjątkiem od tej reguły jest konwersja ciągów. Podczas konwersji a
string
na a[]byte
lub a[]rune
Go działa O (n), nawet jeśli konwersje są „składniowe”.Nie ma standardowej funkcji biblioteki, która wykonałaby tę konwersję za Ciebie. Możesz zrobić jeden z odbiciem, ale byłby wolniejszy niż opcja trzech linii.
Przykład z refleksją:
Najlepszą opcją jest jednak użycie wierszy kodu podanych w pytaniu:
źródło
map
s zbyt btw.channels
również również.Converting a []string to an interface{} is also done in O(1) time
?Brakuje tego,
T
ainterface{}
która ma wartość polegającą na tym,T
że ma różne reprezentacje w pamięci, więc nie można jej trywialnie przekonwertować.Zmienna typu
T
jest tylko jej wartością w pamięci. Brak powiązanych informacji o typie (w Go każda zmienna ma jeden typ znany w czasie kompilacji, a nie w czasie wykonywania). Jest on reprezentowany w pamięci w następujący sposób:Trzymanie
interface{}
zmiennej typuT
jest reprezentowane w pamięci w ten sposóbT
Wracając do pierwotnego pytania: dlaczego go nie jest domyślnie konwertowany
[]T
na[]interface{}
?Konwersja
[]T
na[]interface{}
wymagałaby utworzenia nowego wycinkainterface {}
wartości, co nie jest trywialną operacją, ponieważ układ w pamięci jest zupełnie inny.źródło
Oto oficjalne wyjaśnienie: https://github.com/golang/go/wiki/InterfaceSlice
źródło
[]interface
na oczekiwany typ, taki jak[]map[string]interface{}
?Spróbuj
interface{}
zamiast tego. Aby odrzucić jako plasterek, spróbujźródło
bar
, aby zinterpretować go jako „plasterek dowolnego rodzaju”? Zwróć uwagę, że jego trójwarstwowa warstwa tworzy[]interface{}
, nie[]string
lub plasterek innego rodzaju betonu.func foo(bar []string) { /* ... */ }
interface{}
sprawi, że kompilator nie będzie narzekał podczas przekazywania argumentu jak wfoo(a)
. Mógłby użyć przełączania refleksji lub przełączania typów ( golang.org/doc/effective_go.html#type_switch ) w środkufoo
.Konwertuj
interface{}
na dowolny typ.Składnia:
Przykład:
źródło
invalid type assertion: potato.([]string) (non-interface type []interface {} on left)
Jeśli potrzebujesz więcej skrótów kodu, możesz utworzyć nowy typ pomocnika
następnie
źródło