为什么我不能使用指向期望*interface {}的特定类型的指针?

big*_*ind 3 pointers typechecking go

我有以下功能:

func bytesToData(data interface{}, b []byte) error {
    buf := bytes.NewBuffer(b)
    dec := gob.NewDecoder(buf)
    return dec.Decode(data)
}
Run Code Online (Sandbox Code Playgroud)

我使用它来获取进出boltdb的struct数据.我想做的是将签名更改为:

func bytesToData(data *interface{}, b []byte) error
Run Code Online (Sandbox Code Playgroud)

然后我希望能够像这样调用它(b在这种情况下是一个gob编码的Account)

acc := &Account{}
err := bytesToData(acc, b)
Run Code Online (Sandbox Code Playgroud)

但是,当我这样做时,我得到一个错误Cannot use *Account for type *interface{}.

现在,我刚刚把它改回来了interface{}.但是,如果我Account直接传入一个或其他类型而不使它成为指针,gob会抛出一个错误.看起来这应该在编译时可以检查.并且假设类型的参数interface{}接受任何东西,为什么类型的参数不*interface{}接受指向任何东西的指针?

and*_*olm 7

Go中接口类型的通用性不会传递给派生类型.这适用于指针(如您所注意到的),也适用于切片,通道等.例如,您不能将a指定[]string给a []interface{}.

有各种方法可以解释这一点.对于Haskell程序员:

Go没有协变或逆变类型.所有类型构造函数(例如*创建指针类型)都是不变的.因此即使Account*Account(以及所有其他类型)都是子类型interface{},也没有什么是*interface{}or 的子类型[]interface{}.这有时不方便,但它使Go的类型系统和可分配性规则更加简单.

对于C程序员:

一个interface{}可以保存任何类型的值,但它不能直接保存它.它不是一个可变大小的魔术容器,而是一个由指向类型的指针和指向值的指针组成的结构.当您为a指定具体类型时interface{},将填充这两个字段.*interface{}是指向其中一个结构的指针.当您尝试将a分配*Account给a时*interface{},无处可放置类型信息,因为它*interface{}是一个只包含指针的单个机器字.所以编译器不会让你这样做.

  • 喜欢Haskell / C对比的极端之处。 (2认同)