【问题标题】:Why can't I pass a `func() []int` as `func() []interface{}` in go?为什么我不能在 go 中将 `func() []int` 作为 `func() []interface{}` 传递?
【发布时间】:2018-04-03 23:13:08
【问题描述】:

我有以下定义:

func (c *Collector) RegisterSource(f func() []interface{}) {
    c.source = f
}

我尝试如下调用它,但得到一个错误:

func source() []int {
    return []int{ 0, 1, 2, 3, 4 }
}
...
c.RegisterSource(source)

遇到这样的情况:

cannot use source (type func() []int) as type func() []interface {} in argument to c.RegisterSource

【问题讨论】:

标签: go interface


【解决方案1】:

relevant Go FAQ entry 声明 []T[]interface{} «在内存中没有相同的表示形式»。

要了解原因,让我们剖析两件事:

  1. 切片是一个后备存储array 加上几个包含大小和容量的整数 切片。

    在 Go 中,数组不是某种“高级”;相反, 它们包含的元素的布局是严格定义的:它们都是 包含在一个连续的内存区域中,彼此相邻。

    这意味着,在切片 []T 的后备数组中,元素是 输入T,它们中的每一个都占据一个自然大小的内存区域 对于该类型T,并且所有这些区域都彼此相邻 在单个连续的内存块中。

    这意味着,切片[]int 的每个元素恰好占用 64 位 (8 字节)在 64 位平台上 - 单个 int 值的内存量 占据。

  2. 任何接口类型的值,包括空接口, interface{},表示为一个包含两个指针的结构, 类似:

    type iface struct {
        realType  *typeInfo
        realValue *dataType
    }
    

    (有关如何表示接口的更多信息 - here)。

以上所有的意思是在一个切片[]interface{}每个元素占据 两个指针大小的内存区域,这两个指针包含 内存中其他变量的地址——而不是单纯的整数值 包含在[]int 的元素中。

而这反过来又意味着你不能仅仅“转换”[]int“到”[]interface{}——仅仅因为存储在[]intint)的任何元素中的值是 其结构(内存布局)与元素不兼容 []interface{} (一个包含两个指针的结构)。 要从另一个生成一个,您需要分配一个切片并转换每个切片 源切片的元素与目标切片的匹配元素。

最后,这意味着如果一个函数返回一个[]int类型的切片, 该切片不能由期望切片的代码直接处理 输入[]interface{}(反之亦然),这就解释了原因 您问题中的两个函数签名表示不兼容 类型。

【讨论】:

    【解决方案2】:

    因为 []int 和 []interface 是 2 种不同类型的 slice,而 go 不允许在 2 之间进行自动转换。

    https://github.com/golang/go/wiki/InterfaceSlice

    你能做的就是改变这个

    func source() []int {
        return []int{ 0, 1, 2, 3, 4 }
    }
    

    进入那个

    func source() []interface{} {
        return []interface{}{ 0, 1, 2, 3, 4 }
    }
    

    为了适合您为RegisterSource 定义的函数签名。

    【讨论】:

      猜你喜欢
      • 2022-06-16
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 1970-01-01
      • 2012-04-18
      • 1970-01-01
      • 2019-07-18
      相关资源
      最近更新 更多