简体   繁体   中英

Why can't I use a pointer to a specific type where *interface{} is expected?

I have the following function:

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

I use this for getting struct data in and out of boltdb. What I'd like to do, is change that signature to:

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

And then I'd like to be able to call it like this ( b in this case is a gob-encoded Account )

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

But when I do that, I get an error like Cannot use *Account for type *interface{} .

For now, I've just changed it back to interface{} . But then, if I pass in an Account or some other type directly without making it a pointer, gob throws an error. It seems like this should be checkable at compile time. And given that an argument of type interface{} accepts anything, why doesn't an argument of type *interface{} accept a pointer to anything?

The genericity of interface types in Go is not passed on to derived types. This applies to pointers (as you noticed), and also to slices, channels, etc. For example, you can't assign a []string to a []interface{} .

There are various ways to explain this. For a Haskell programmer:

Go does not have covariant or contravariant types. All type constructors (such as the * that creates a pointer type) are invariant. So even though Account and *Account (and all other types) are subtypes of interface{} , nothing is a subtype of *interface{} or []interface{} . This is sometimes inconvenient, but it keeps Go's type system and assignability rules much simpler.

For a C programmer:

An interface{} can hold a value of any type, but it does not hold it directly. Rather than being a variable-sized magic container, it is just a struct consisting of a pointer to a type and a pointer to a value. When you assign a concrete type to an interface{} , both of these fields are filled in. *interface{} is a pointer to one of these structs. When you try to assign a *Account to a *interface{} , there is nowhere to put the type information, because the *interface{} is a single machine word that just holds a pointer. So the compiler won't let you do that.

interface{} could also contain a pointer with no problem. But there is nothing like a pointer to interface{}

See these:

Cast a struct pointer to interface pointer in Golang

Why can't I assign a *Struct to an *Interface?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM