在go中键入转换接口片
我很好奇,为什么go不会隐式地把T
转换为[]interface{}
当它隐式地将T
转换为interface{}
。 有没有什么不重要的转换,我失踪了?
例:
func foo([]interface{}) { /* do something */ } func main() { var a []string = []string{"hello", "world"} foo(a) }
go build
抱怨
在函数参数中不能使用(type [] string)作为type [] interface {}
如果我试图明确地做,同样的事情: b := []interface{}(a)
抱怨
无法将(type []string)转换为键入[] interface {}
所以每次我需要做这个转换(这似乎出现了很多),我一直在做这样的事情:
b = make([]interface{}, len(a), len(a)) for i := range a { b[i] = a[i] }
有没有更好的方法来做到这一点,或标准库函数来帮助这些转换? 每次我想调用一个函数,例如整数或string的列表时,编写4行额外的代码似乎是很愚蠢的。
在Go中,通常的规则是语法不应该隐藏复杂/昂贵的操作。 将string
转换为interface{}
在O(1)时间内完成。 将[]string
转换为interface{}
也是在O(1)时间内完成的,因为切片仍然是一个值。 但是,将[]string
转换为[]interface{}
是O(n),因为切片的每个元素必须转换为interface{}
。
这个规则的一个例外是转换string。 当将string
转换为[]byte
或[]rune
,即使转换为“语法”,Go也会运行O(n)。
没有标准的库函数会为你做这个转换。 你可以做一个反映,但它会比三线选项慢。
reflection示例:
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 }
尽pipe你最好的select只是使用你在你的问题中给出的代码行:
b := make([]interface{}, len(a)) for i := range a { b[i] = a[i] }
你缺less的东西是T
和interface{}
,它保存了一个值T
在内存中有不同的表示,所以不能被简单地转换。
T
types的variables在内存中只是其值。 没有关联的types信息(在Go中每个variables都有一个在编译时已知的types,而不是在运行时)。 像这样在记忆中performance出来
- 值
一个保存T
typesvariables的interface{}
就像这样在内存中表示
- 指向types
T
指针 - 值
所以回到你原来的问题:为什么不会隐式地将[]T
转换为[]interface{}
?
将[]T
转换为[]interface{}
将涉及创build一个新的interface {}
值,这是一个不平凡的操作,因为内存布局是完全不同的。
这里是官方的解释: 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 }
尝试使用interface{}
。 要退后一步,试试
func foo(bar interface{}) { s := bar.([]string) // ... }