reflect golang example go go-reflect go-interface

golang - Escriba convertir segmentos de interfaces en go



go reflection (4)

Aquí está la explicación oficial: 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 }

Tengo curiosidad por saber por qué go no convierte implícitamente []T en []interface{} cuando implícitamente convertirá T en interface{} . ¿Hay algo no trivial acerca de esta conversión que me falta?

Ejemplo:

func foo([]interface{}) { /* do something */ } func main() { var a []string = []string{"hello", "world"} foo(a) }

go build queja

no puede usar una cadena (tipo []) como tipo [] interfaz {} en argumento de función

Y si trato de hacerlo explícitamente, lo mismo: b := []interface{}(a) queja

no se puede convertir una (tipo [] cadena) en escribir [] interfaz {}

Así que cada vez que necesito hacer esta conversión (que parece surgir mucho), he estado haciendo algo como esto:

b = make([]interface{}, len(a), len(a)) for i := range a { b[i] = a[i] }

¿Hay alguna forma mejor de hacerlo, o funciones de biblioteca estándar para ayudar con estas conversiones? Parece una tontería escribir 4 líneas adicionales de código cada vez que quiero llamar a una función que puede tomar una lista de, por ejemplo, enter o cadenas.


En Go, existe una regla general de que la sintaxis no debe ocultar operaciones complejas / costosas. La conversión de una string a una interface{} se realiza en O (1) tiempo. La conversión de una []string a una interface{} también se realiza en el tiempo O (1) ya que una porción sigue siendo un valor. Sin embargo, la conversión de una []string a una []interface{} es O (n) tiempo porque cada elemento de la división debe convertirse a una interface{} .

La única excepción a esta regla es la conversión de cadenas. Al convertir una string hacia y desde un []byte o una []rune , Go hace que O (n) funcione aunque las conversiones sean "sintaxis".

No hay una función de biblioteca estándar que realice esta conversión por usted. Podría hacer uno con reflejo, pero sería más lento que la opción de tres líneas.

Ejemplo con reflexión:

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 }

Sin embargo, su mejor opción es usar las líneas de código que dio en su pregunta:

b := make([]interface{}, len(a)) for i := range a { b[i] = a[i] }


Lo que te falta es que T y la interface{} que tiene un valor de T tienen diferentes representaciones en la memoria, por lo que no se pueden convertir trivialmente.

Una variable de tipo T es solo su valor en la memoria. No hay información de tipo asociada (en Go, cada variable tiene un único tipo conocido en tiempo de compilación, no en tiempo de ejecución). Está representado en una memoria como esta:

  • valor

Una interface{} contiene una variable de tipo T se representa en una memoria como esta

  • puntero para escribir T
  • valor

Volviendo a su pregunta original: ¿por qué go no convierte implícitamente []T a []interface{} ?

La conversión de []T en []interface{} implicaría la creación de una nueva porción de valores de interface {} que es una operación no trivial ya que el diseño en memoria es completamente diferente.


Pruebe la interface{} lugar. Para volver a lanzar como una rebanada, intenta

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