Golang的[]interface{}为什么不能接收[]int?

烧麦
  • 212

先看第一个例子:

func main() {
    var i int =6
    test(i)
}

func test(i interface{}) {
    fmt.Println(i)
}

上面代码运行成功,输出6

我们再看另外一种代码:

func main() {
    is := []int{7, 8, 9, 10}
    test(is) // cannot use is (type []int) as type []interface {} in argument to test
}

func test(i []interface{}) {
    fmt.Println(i)
}

上面代码报错,cannot use is (type []int) as type []interface {} in argument to test。虽然我知道报错的意思,但是不明白为什么?结合2个demo,就有点懵圈。

有知道的大神帮忙解答一下,谢谢!!

回复
阅读 1.3k
3 个回答

int 不是 interface{} ,所以 []int 不是 []interface{}。而且也无法转化。

int 可以转换为 interface{} ,所以第一个例子是可以通过的。

因为内置的slice没有协变/逆变支持,go的类型系统在这块是不完整的。具体自己搜什么叫协变/逆变。

官方的issues里有相关讨论,目前没有任何进展。个人看法是一直到go2也不会直接支持。建议自己看下原issue的讨论和解释。

目前的临时处理方法可以是用1.18的泛型实现一个转换函数。

麻瓜
  • 112

golang 的类型系统规定 interface{} 是空接口, 任何类型的对象都默认实现了空接口; 所以如果函数的入参是 interface{} 时, 传入函数的参数会进行隐式类型转换为 interface{} 类型:

func main() {
    is := []int{7, 8, 9, 10}
    test(is) 
}

func test(i interface{}) {
    fmt.Println(i)
}

在 test 函数中, 你传入的参数 i 的类型是 slice 被隐式转换为 interface{}, 传入 fmt.Println 后, 会被反射 reflect 解析为 reflect.Slice 处理后打印;
注意,[]interface{} 和 interface{} 是不同的类型, 所以在传参时并不会做类似的隐式类型转换, 观察以下例子是可以正常运行的:

func main() {
    is := []int{7, 8, 9, 10}
    var mis []interface{}
    mis = append(mis, is)
    test(mis)
}


func test(i []interface{}) {
    fmt.Println(i)
}

再看 fmt.Println 函数的签名:

func Println(a ...interface{}) (n int, err error) {
    return Fprintln(os.Stdout, a...)         
}                                                                         

可变参数 a 代表传入任意多个的 interface{}, 所以类型为 []interface{} 的变量 i 可以作为 fmt.Println 的参数;
例子中的报错信息
cannot use is (type []int) as type []interface {} in argument to test
可以替换为
cannot use is (type slice) as type []interface {} in argument to test
因为 slice 类型实现了为 interface{}, 但其类型不是 []interface{} 类型;

由此, golang 的编译器会报错

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