类型转换接口切片

新手上路,请多包涵

I’m curious why Go does’t implicitly convert []T to []interface{} when it will implicitly convert T to 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) 转换为 type []interface {}

所以每次我需要做这个转换(这似乎出现了很多),我一直在做这样的事情:

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

是否有更好的方法或标准库函数来帮助进行这些转换?每次我想调用一个可以获取列表(例如整数或字符串)的函数时,多写 4 行代码似乎有点愚蠢。

原文由 danny 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 478
2 个回答

在 Go 中,有一个通用规则,即 语法不应隐藏复杂/昂贵的操作

string 转换为 interface{} 在 O(1) 时间内完成。将 []string 转换为 interface{} 也在 O(1) 时间内完成,因为切片仍然是一个值。但是,将 []string 转换为 []interface{} 是 O(n) 时间,因为切片的每个元素都必须转换为 interface{}

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

没有标准库函数可以为您进行这种转换。不过,您最好的选择就是使用您在问题中提供的代码行:

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

否则,您可以使用 reflect 制作一个,但它会比三行选项慢。反射示例:

 func InterfaceSlice(slice interface{}) []interface{} {
    s := reflect.ValueOf(slice)
    if s.Kind() != reflect.Slice {
        panic("InterfaceSlice() given a non-slice type")
    }

    // Keep the distinction between nil and empty slice input
    if s.IsNil() {
        return nil
    }

    ret := make([]interface{}, s.Len())

    for i:=0; i<s.Len(); i++ {
        ret[i] = s.Index(i).Interface()
    }

    return ret
}

原文由 Stephen Weinberg 发布,翻译遵循 CC BY-SA 4.0 许可协议

您缺少的是 Tinterface{} 其值为 T 在内存中具有不同的表示形式,因此无法简单地转换。

类型为 T 的变量只是它在内存中的值。没有关联的类型信息(在 Go 中,每个变量都有一个在编译时已知的类型,而不是在运行时已知的类型)。它在内存中是这样表示的:

  • 价值

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

  • 指向类型的指针 T
  • 价值

所以回到你最初的问题:为什么 go 不隐式转换 []T[]interface{}

[]T 转换为 []interface{} 将涉及创建一个新的 interface {} 值的切片,因为这是一个完全不同的操作。

原文由 Nick Craig-Wood 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题