web-dev-qa-db-fra.com

Tapez les tranches de conversion d'interfaces

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.

162
danny

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]
}
175
Stephen Weinberg

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:

  • valeur

Un interface{} contenant une variable de type T est représenté en mémoire comme ceci

  • pointeur pour taper T
  • valeur

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.

45
Nick Craig-Wood

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
}
10
Yandry Pozo

Essayez interface{} au lieu. Pour lancer en arrière, essayez

func foo(bar interface{}) {
    s := bar.([]string)
    // ...
}
5
dskinner

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.
2
yala ramesh