Ich bin neugierig , warum implizit Go does't konvertieren []T
zu , []interface{}
wenn es implizit konvertieren T
zu interface{}
. Gibt es etwas nicht Triviales an dieser Konvertierung, das mir fehlt?
Beispiel:
func foo([]interface{}) { /* do something */ }
func main() {
var a []string = []string{"hello", "world"}
foo(a)
}
go build
beschwert sich
kann keine (Typ [] Zeichenfolge) als Typ [] Schnittstelle {} im Funktionsargument verwenden
Und wenn ich es explizit versuche, dasselbe: sich b := []interface{}(a)
beschweren
Ein (Typ [] String) kann nicht in Typ [] Schnittstelle {} konvertiert werden
Jedes Mal, wenn ich diese Konvertierung durchführen muss (was sehr häufig vorkommt), habe ich so etwas gemacht:
b = make([]interface{}, len(a), len(a))
for i := range a {
b[i] = a[i]
}
Gibt es eine bessere Möglichkeit, dies zu tun, oder Standardbibliotheksfunktionen, um bei diesen Konvertierungen zu helfen? Es scheint irgendwie albern, jedes Mal, wenn ich eine Funktion aufrufen möchte, die eine Liste von z. B. Ints oder Strings aufnehmen kann, 4 zusätzliche Codezeilen zu schreiben.
quelle
Antworten:
In Go gibt es eine allgemeine Regel, nach der die Syntax komplexe / kostspielige Vorgänge nicht verbergen soll. Die Konvertierung von a
string
in ainterface{}
erfolgt in O (1) -Zeit. Das Konvertieren von a[]string
in ainterface{}
erfolgt ebenfalls in O (1) -Zeit, da ein Slice immer noch einen Wert hat. Die Konvertierung von a[]string
in a[]interface{}
ist jedoch O (n), da jedes Element des Slice in eine konvertiert werden mussinterface{}
.Die einzige Ausnahme von dieser Regel ist das Konvertieren von Zeichenfolgen. Beim Konvertieren von a
string
nach und von a[]byte
oder a[]rune
funktioniert Go mit O (n), obwohl Konvertierungen "Syntax" sind.Es gibt keine Standardbibliotheksfunktion, die diese Konvertierung für Sie durchführt. Sie könnten eine mit Reflect erstellen, diese ist jedoch langsamer als die Option mit drei Zeilen.
Beispiel mit Reflexion:
Ihre beste Option ist jedoch, nur die Codezeilen zu verwenden, die Sie in Ihrer Frage angegeben haben:
quelle
map
übrigens auch für s.channels
.Converting a []string to an interface{} is also done in O(1) time
?Das , was Sie fehlt, ist , dass
T
undinterface{}
die einen Wert von hältT
haben unterschiedliche Darstellungen im Speicher so nicht triviale Weise umgewandelt werden können.Eine Variable vom Typ
T
ist nur ihr Wert im Speicher. Es sind keine Typinformationen zugeordnet (in Go hat jede Variable einen einzelnen Typ, der zur Kompilierungszeit und nicht zur Laufzeit bekannt ist). Es wird im Gedächtnis wie folgt dargestellt:Ein
interface{}
Halten einer Variablen vom TypT
wird im Speicher wie folgt dargestelltT
Kommen wir also zu Ihrer ursprünglichen Frage zurück: Warum konvertiert go nicht implizit
[]T
zu[]interface{}
?Das Konvertieren
[]T
in[]interface{}
würde das Erstellen einer neuen Wertscheibe umfasseninterface {}
, was nicht trivial ist, da das speicherinterne Layout völlig anders ist.quelle
Hier ist die offizielle Erklärung: https://github.com/golang/go/wiki/InterfaceSlice
quelle
[]interface
in den Typ konvertieren , den ich erwarte, wie z[]map[string]interface{}
.Versuchen Sie es
interface{}
stattdessen. Versuchen Sie es, um es als Scheibe zurückzuwerfenquelle
bar
, um es als "Slice jeglichen Typs" zu interpretieren? Beachten Sie, dass sein Dreiliner eine[]interface{}
, keine[]string
oder eine Scheibe eines anderen Betontyps erzeugt.func foo(bar []string) { /* ... */ }
interface{}
, beschwert sich der Compiler nicht, wenn Sie ein Argument wie in übergebenfoo(a)
. Er könnte entweder Reflect oder Type Switching ( golang.org/doc/effective_go.html#type_switch ) verwendenfoo
.interface{}
In einen beliebigen Typ konvertieren .Syntax:
Beispiel:
quelle
invalid type assertion: potato.([]string) (non-interface type []interface {} on left)
Falls Sie mehr Kurzschluss für Ihren Code benötigen, können Sie einen neuen Typ für den Helfer erstellen
dann
quelle