Digitare le sezioni di conversione delle interfacce in go

Sono curioso di sapere perché go non converte implicitamente []T in []interface{} quando converte implicitamente T in interface{} . C’è qualcosa di non banale in questa conversione che mi manca?

Esempio:

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

go build lamentele

non è ansible utilizzare un (tipo [] stringa) come tipo [] interface {} nell’argomento della funzione

E se provo a farlo esplicitamente, la stessa cosa: b := []interface{}(a) lamenta

imansible convertire un (tipo [] stringa) per digitare [] interface {}

Quindi ogni volta che ho bisogno di fare questa conversione (che sembra venire molto), ho fatto qualcosa del genere:

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

C’è un modo migliore per farlo, o le funzioni della libreria standard per aiutare con queste conversioni? Sembra un po ‘sciocco scrivere 4 linee in più di codice ogni volta che voglio chiamare una funzione che può prendere una lista di interi o stringhe.

In Go, esiste una regola generale per la quale la syntax non deve hide operazioni complesse / costose. La conversione di una string in interface{} viene eseguita in tempo O (1). La conversione di una []string in interface{} viene eseguita anche in tempo O (1) poiché una porzione ha ancora un valore. Tuttavia, la conversione di una []string []interface{} è O (n), poiché ogni elemento della sezione deve essere convertito in interface{} .

L’unica eccezione a questa regola è la conversione delle stringhe. Quando converti una string in e da una []byte o una []rune , Go fa O (n) funziona anche se le conversioni sono “syntax”.

Non esiste una funzione di libreria standard che eseguirà questa conversione per te. Potresti farne uno con reflect, ma sarebbe più lento dell’opzione a tre linee.

Esempio con riflessione:

 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 

La tua opzione migliore però è solo quella di usare le linee di codice che hai dato nella tua domanda:

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

La cosa che ti manca è che T e interface{} che detengono un valore di T hanno diverse rappresentazioni in memoria, quindi non possono essere convertite banalmente.

Una variabile di tipo T è solo il suo valore in memoria. Non ci sono informazioni sul tipo associato (in Vai ogni variabile ha un singolo tipo noto al momento della compilazione non in fase di esecuzione). È rappresentato in memoria come questo:

  • valore

Un’interfaccia interface{} che contiene una variabile di tipo T è rappresentata in memoria come questa

  • puntatore a digitare T
  • valore

Quindi tornando alla tua domanda iniziale: perché go non converte implicitamente []T in []interface{} ?

La conversione da []T a []interface{} implicherebbe la creazione di una nuova porzione di interface {} valori che è un’operazione non banale poiché il layout in memoria è completamente diverso.

Ecco la spiegazione ufficiale: 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 } 

Prova invece l’ interface{} . Per tornare indietro come una fetta, prova

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