Je suis curieux de savoir pourquoi Go ne se convertit []T
pas implicitement en []interface{}
quand il se convertira implicitement T
en interface{}
. Y a-t-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
impossible d'utiliser une chaîne (type []) comme type [] interface {} dans l'argument de la fonction
Et si j'essaye de le faire explicitement, même chose: se b := []interface{}(a)
plaindre
impossible de convertir une (type [] string) en type [] interface {}
Donc, chaque fois que j'ai besoin de faire cette conversion (ce qui semble arriver souvent), j'ai fait quelque chose comme ceci:
b = make([]interface{}, len(a), len(a))
for i := range a {
b[i] = a[i]
}
Existe-t-il une meilleure façon de faire cela, ou des fonctions de bibliothèque standard pour aider à ces conversions? Cela semble un peu idiot d'écrire 4 lignes de code supplémentaires chaque fois que je veux appeler une fonction qui peut prendre une liste d'ints ou de chaînes, par exemple.
la source
Réponses:
Dans Go, il existe une règle générale selon laquelle la syntaxe ne doit pas masquer les opérations complexes / coûteuses. La conversion de a
string
en aninterface{}
se fait en temps O (1). La conversion de a[]string
en aninterface{}
se fait également en temps O (1) car une tranche est toujours une valeur. Cependant, la conversion de a[]string
en an[]interface{}
est un temps O (n) car chaque élément de la tranche doit être converti en uninterface{}
.La seule exception à cette règle est la conversion de chaînes. Lors de la conversion de a
string
vers et depuis a[]byte
ou a[]rune
, Go fait O (n) fonctionne même si les conversions sont "syntaxiques".Il n'y a pas de fonction de bibliothèque standard qui fera cette conversion pour vous. Vous pouvez en créer un avec Reflect, mais ce serait plus lent que l'option à trois lignes.
Exemple avec réflexion:
Votre meilleure option est cependant simplement d'utiliser les lignes de code que vous avez fournies dans votre question:
la source
map
s trop btw.channels
.Converting a []string to an interface{} is also done in O(1) time
?La chose qui vous manque est celle-là
T
etinterface{}
qui détient une valeur deT
avoir différentes représentations en mémoire et ne peut donc pas être convertie de manière triviale.Une variable de type
T
est juste sa valeur en mémoire. Il n'y a pas d'informations de type associées (dans Go, chaque variable a un seul type connu au moment de la compilation et non au moment de l'exécution). Il est représenté en mémoire comme ceci:Un
interface{}
tenant une variable de typeT
est représenté en mémoire comme ceciT
Revenons donc à votre question initiale: pourquoi aller n'est-il pas implicitement converti
[]T
en[]interface{}
?La conversion
[]T
en[]interface{}
impliquerait la création d'une nouvelle tranche deinterface {}
valeurs, ce qui est une opération non triviale car la disposition en mémoire est complètement différente.la source
Voici l'explication officielle: https://github.com/golang/go/wiki/InterfaceSlice
la source
[]interface
au type auquel je m'attends, par exemple[]map[string]interface{}
?Essayez à la
interface{}
place. Pour reconstituer une tranche, essayezla source
bar
pour l'interpréter comme "une tranche de n'importe quel type"? Notez que son triple revêtement crée un[]interface{}
, pas[]string
ou une tranche d'un autre type de béton.func foo(bar []string) { /* ... */ }
interface{}
empêchera le compilateur de se plaindre lors de la transmission d'un argument comme dansfoo(a)
. Il pourrait soit utiliser refléter ou taper la commutation ( golang.org/doc/effective_go.html#type_switch ) à l'intérieurfoo
.Convertissez
interface{}
en n'importe quel type.Syntaxe:
Exemple:
la source
invalid type assertion: potato.([]string) (non-interface type []interface {} on left)
Au cas où vous auriez besoin de raccourcir plus votre code, vous pouvez créer un nouveau type pour helper
puis
la source