在Go中键入转换接口切片

时间:2012-10-05 20:48:07

标签: go go-reflect go-interface

我很好奇为什么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 []字符串)转换为类型[] interface {}

所以每次我需要进行这种转换(这似乎很多),我一直在做这样的事情:

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

有更好的方法可以执行此操作,还是使用标准库函数来帮助完成这些转换?每次我想调用一个可以获取例如一个列表的函数时,编写4行额外代码似乎有点愚蠢。整数或字符串。

6 个答案:

答案 0 :(得分:163)

在Go中,一般规则是语法不应隐藏复杂/昂贵的操作。将string转换为interface{}是在O(1)时间内完成的。将[]string转换为interface{}也是在O(1)时间内完成的,因为切片仍然是一个值。但是,将[]string转换为[]interface{}的时间为O(n),因为切片的每个元素都必须转换为interface{}

此规则的一个例外是转换字符串。将string转换为[]byte[]rune时,Go会执行O(n)工作,即使转换是“语法”。

没有标准库函数可以为您执行此转换。你可以使用reflect来制作一个,但它会比三行选项慢。

反射示例:

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
}

您最好的选择就是使用您在问题中提供的代码行:

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

答案 1 :(得分:42)

您遗失的是Tinterface{},其值T在内存中具有不同的表示形式,因此无法轻易转换。

T类型的变量就是它在内存中的值。没有关联的类型信息(在Go中,每个变量在编译时都知道一种类型,而不是在运行时)。它在内存中表示如下:

持有interface{}类型变量的T在内存中表示如下

  • 指向T
  • 类型的指针

回到原来的问题:为什么不能隐含地将[]T转换为[]interface{}

[]T转换为[]interface{}将涉及创建新的interface {}值切片,这是一项非常重要的操作,因为内存中布局完全不同。

答案 2 :(得分:8)

以下是官方解释: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
}

答案 3 :(得分:6)

请尝试使用interface{}。要转换为切片,请尝试

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

答案 4 :(得分:4)

万一您需要缩短代码长度,可以为助手创建新类型

type Strings []string

func (ss Strings) ToInterfaceSlice() []interface{} {
    iface := make([]interface{}, len(ss))
    for i := range ss {
        iface[i] = ss[i]
    }
    return iface
}

然后

a := []strings{"a", "b", "c", "d"}
sliceIFace := Strings(a).ToInterfaceSlice()

答案 5 :(得分:1)

interface{}转换为任何类型。

语法:

result := interface.(datatype)

示例:

var employee interface{} = []string{"Jhon", "Arya"}
result := employee.([]string)   //result type is []string.