Estou curioso para saber por que o Go não se converte implicitamente []T
em []interface{}
quando implicitamente se converte T
em interface{}
. Há algo não trivial nessa conversão que estou perdendo?
Exemplo:
func foo([]interface{}) { /* do something */ }
func main() {
var a []string = []string{"hello", "world"}
foo(a)
}
go build
reclama
não pode usar um (tipo [] string) como tipo [] interface {} no argumento da função
E se eu tentar explicitamente, a mesma coisa: b := []interface{}(a)
reclama
não é possível converter uma (tipo [] string) para digitar [] interface {}
Então, toda vez que preciso fazer essa conversão (o que parece surgir bastante), tenho feito algo assim:
b = make([]interface{}, len(a), len(a))
for i := range a {
b[i] = a[i]
}
Existe uma maneira melhor de fazer isso, ou funções de biblioteca padrão para ajudar com essas conversões? Parece meio bobo escrever 4 linhas de código extras toda vez que eu quiser chamar uma função que pode ter uma lista de, por exemplo, ints ou strings.
fonte
Respostas:
No Go, existe uma regra geral de que a sintaxe não deve ocultar operações complexas / caras. A conversão de um
string
para uminterface{}
é feita no tempo O (1). A conversão de um[]string
para uminterface{}
também é feita no tempo O (1), pois uma fatia ainda é um valor. No entanto, converter a[]string
em um[]interface{}
é tempo O (n) porque cada elemento da fatia deve ser convertido em uminterface{}
.A única exceção a esta regra é a conversão de cadeias. Ao converter um
string
para e de um[]byte
ou a[]rune
, Go funciona O (n), mesmo que as conversões sejam "sintaxe".Não há função de biblioteca padrão que faça essa conversão para você. Você poderia fazer um com refletir, mas seria mais lento que a opção de três linhas.
Exemplo com reflexão:
Sua melhor opção é apenas usar as linhas de código que você forneceu na sua pergunta:
fonte
map
s também.channels
também.Converting a []string to an interface{} is also done in O(1) time
?A coisa que está faltando é que
T
einterface{}
que detém um valor deT
ter diferentes representações na memória de modo não pode ser trivialmente convertido.Uma variável do tipo
T
é apenas o seu valor na memória. Não há informações de tipo associadas (no Go, cada variável possui um único tipo conhecido no tempo de compilação e não no tempo de execução). É representado na memória assim:Uma
interface{}
retenção de uma variável do tipoT
é representada na memória como estaT
Voltando à sua pergunta original: por que ir não é convertido implicitamente
[]T
em[]interface{}
?A conversão
[]T
para[]interface{}
envolveria a criação de uma nova fatia deinterface {}
valores, que é uma operação não trivial, pois o layout da memória é completamente diferente.fonte
Aqui está a explicação oficial: https://github.com/golang/go/wiki/InterfaceSlice
fonte
[]interface
para o tipo que espero, como[]map[string]interface{}
?Tente em
interface{}
vez disso. Para converter de volta como fatia, tentefonte
bar
para interpretá-lo como "uma fatia de qualquer tipo"? Observe que o revestimento de três camadas cria um[]interface{}
, não[]string
ou uma fatia de outro tipo de concreto.func foo(bar []string) { /* ... */ }
interface{}
fará com que o compilador não se queixe ao passar um argumento como emfoo(a)
. Ele poderia usar refletir ou digitar switching ( golang.org/doc/effective_go.html#type_switch ) dentrofoo
.Converta
interface{}
em qualquer tipo.Sintaxe:
Exemplo:
fonte
invalid type assertion: potato.([]string) (non-interface type []interface {} on left)
Caso precise de um código mais curto, você pode criar um novo tipo para helper
então
fonte