2017-07-01 90 views
0

我有以下功能:为什么我不能使用指向* interface {}的特定类型的指针?

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

我用这个进出boltdb的获得结构数据。我想要做的,就是改变这种签名:

func bytesToData(data *interface{}, b []byte) error 

然后,我希望能够这样称呼它(b在这种情况下是采空区编码Account

acc := &Account{} 
err := bytesToData(acc, b) 

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

现在,我刚刚将其更改回interface{}。但是,如果我直接传入Account或其他某种类型而不使其成为指针,则gob会抛出错误。这似乎应该在编译时检查。并且假设类型为interface{}的参数接受任何内容,为什么*interface{}类型的参数不接受指向任何内容的指针?

回答

3

在Go接口类型的通用性不上派生类型传递。这适用于指针(如您注意的),以及切片,通道等。例如,您不能将[]string分配给[]interface{}

有多种方式可以解释这一点。对于Haskell程序员:

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

对于C程序员:

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

+0

爱上Haskell/C对比的极端。 –

相关问题