Je suis curieux de savoir pourquoi Go ne convertit pas implicitement []T
En []interface{}
Lorsqu'il convertira implicitement T
en interface{}
. Y at-il quelque chose de non trivial dans cette conversion qui me manque?
Exemple:
func foo([]interface{}) { /* do something */ }
func main() {
var a []string = []string{"hello", "world"}
foo(a)
}
go build
Se plaint
ne peut pas utiliser une chaîne (type []) comme type [] interface {} dans l'argument de la fonction
Et si j'essaie de le faire explicitement, la même chose: b := []interface{}(a)
se plaint
impossible de convertir une chaîne (de type []) en interface de type [] {}
Donc chaque fois que j'ai besoin de faire cette conversion (ce qui semble être très courant), je fais quelque chose comme ça:
b = make([]interface{}, len(a), len(a))
for i := range a {
b[i] = a[i]
}
Existe-t-il un meilleur moyen de le faire ou des fonctions de bibliothèque standard pour faciliter ces conversions? Il semble un peu bête d’écrire 4 lignes de code supplémentaires chaque fois que je veux appeler une fonction pouvant prendre une liste, par exemple. ints ou ficelles.
Dans Go, il existe une règle générale selon laquelle la syntaxe ne doit pas masquer les opérations complexes/coûteuses. Conversion de string
en interface{}
se fait en O(1) temps. Conversion d’un []string
à un interface{}
est également effectué en O(1) fois, car une tranche est toujours une valeur. Cependant, la conversion d'un []string
à un []interface{}
est O(n) temps car chaque élément de la tranche doit être converti en un interface{}
.
La seule exception à cette règle est la conversion de chaînes. Lors de la conversion d'un string
vers et depuis un []byte
ou un []rune
, Go fonctionne O(n) fonctionne même si les conversions sont une "syntaxe".
Il n'y a pas de fonction de bibliothèque standard qui effectuera cette conversion pour vous. Vous pouvez en créer un avec réflexion, mais ce serait plus lent que l'option à trois lignes.
Exemple avec réflexion:
func InterfaceSlice(slice interface{}) []interface{} {
s := reflect.ValueOf(slice)
if s.Kind() != reflect.Slice {
panic("InterfaceSlice() given a non-slice type")
}
ret := make([]interface{}, s.Len())
for i:=0; i<s.Len(); i++ {
ret[i] = s.Index(i).Interface()
}
return ret
}
Cependant, votre meilleure option consiste simplement à utiliser les lignes de code que vous avez données dans votre question:
b := make([]interface{}, len(a))
for i := range a {
b[i] = a[i]
}
Ce qui vous manque, c'est que T
et interface{}
qui contient une valeur de T
a différentes représentations en mémoire et ne peut donc pas être converti de manière triviale.
Une variable de type T
n'est que sa valeur en mémoire. Il n'y a pas d'informations de type associées (dans Go, chaque variable a un type unique connu à la compilation et non à l'exécution). Il est représenté en mémoire comme ceci:
Un interface{}
contenant une variable de type T
est représenté en mémoire comme ceci
T
Revenons donc à votre question initiale: pourquoi aller ne convertit pas implicitement []T
à []interface{}
?
Conversion []T
à []interface{}
impliquerait la création d’une nouvelle tranche de interface {}
valeurs qui est une opération non triviale puisque la disposition en mémoire est complètement différente.
Voici l'explication officielle: https://github.com/golang/go/wiki/InterfaceSlice
var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
interfaceSlice[i] = d
}
Essayez interface{}
au lieu. Pour lancer en arrière, essayez
func foo(bar interface{}) {
s := bar.([]string)
// ...
}
Convertir interface{}
dans n'importe quel type.
Syntaxe:
result := interface.(datatype)
Exemple:
var employee interface{} = []string{"Jhon", "Arya"}
result := employee.([]string) //result type is []string.