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?
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With