Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 823
bigblind Avatar asked Jul 01 '17 19:07

bigblind


People also ask

Can interface be a pointer?

An interface pointer is a pointer to an object instance that points, in turn, to the implementation of each method in the interface. The implementation is accessed through an array of pointers to these methods, which is called a vtable.

Can an interface be a pointer Golang?

Go's interface values are really a pair of pointers. When you put a concrete value into an interface value, one pointer starts pointing at the value. The second will now point to the implementation of the interface for the type of the concrete value.

Can we assign pointer to integer?

Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.

What do you mean by a pointer to a pointer can this be extended?

A pointer to a pointer is a form of multiple indirection, or a chain of pointers. Normally, a pointer contains the address of a variable. When we define a pointer to a pointer, the first pointer contains the address of the second pointer, which points to the location that contains the actual value as shown below.


1 Answers

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.

like image 97
andybalholm Avatar answered Sep 28 '22 08:09

andybalholm