Matt Joiner
Matt Joiner

Reputation: 118710

Take address of value inside an interface

How do I take the address of a value inside an interface?

I have an struct stored in an interface, in a list.List element:

import "container/list"
type retry struct{}
p := &el.Value.(retry)

But I get this:

cannot take the address of el.Value.(retry)

What's going on? Since the struct is stored in the interface, why can't I get a pointer to it?

Upvotes: 10

Views: 5122

Answers (4)

James Henstridge
James Henstridge

Reputation: 43949

To understand why this isn't possible, it is helpful to think about what an interface variable actually is. An interface value takes up two words, with the first describing the type of the contained value, and the second either (a) holding the contained value (if it fits within the word) or (b) a pointer to storage for the value (if the value does not fit within a word).

The important things to note are that (1) the contained value belongs to the interface variable, and (2) the storage for that value may be reused when a new value is assigned to the variable. Knowing that, consider the following code:

var v interface{}
v = int(42)
p := GetPointerToInterfaceValue(&v) // a pointer to an integer holding 42
v = &SomeStruct{...}

Now the storage for the integer has been reused to hold a pointer, and *p is now an integer representation of that pointer. You can see how this has the capacity to break the type system, so Go doesn't provide a way to do this (outside of using the unsafe package).

If you need a pointer to the structs you're storing in a list, then one option would be to store pointers to the structs in the list rather than struct values directly. Alternatively, you could pass *list.Element values as references to the contained structures.

Upvotes: 12

peterSO
peterSO

Reputation: 166885

Get pointer to interface value?

Is there a way, given a variable of interface type, of getting a pointer to the value stored in the variable?

It is not possible.

Rob Pike

Interface values are not necessarily addressable. For example,

package main

import "fmt"

func main() {
    var i interface{}
    i = 42
    // cannot take the address of i.(int)
    j := &i.(int)
    fmt.Println(i, j)
}

Address operators

For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a composite literal.

References:

Interface types

Type assertions

Go Data Structures: Interfaces

Go Interfaces

Upvotes: 2

thwd
thwd

Reputation: 24878

A type assertion is an expression that results in two values. Taking the address in this case would be ambiguous.

p, ok := el.Value.(retry)
if ok {
    // type assertion successful
    // now we can take the address
    q := &p 
}

From the comments:

Note that this is a pointer to a copy of the value rather than a pointer to the value itself.

James Henstridge

The solution to the problem is therefore simple; store a pointer in the interface, not a value.

Upvotes: 3

zzzz
zzzz

Reputation: 91419

In the first approximation: You cannot do that. Even if you could, p itself would the have to have type interface{} and would not be too helpful - you cannot directly dereference it then.

The obligatory question is: What problem are you trying to solve?

And last but not least: Interfaces define behavior not structure. Using the interface's underlying implementing type directly in general breaks the interface contract, although there might be non general legitimate cases for it. But those are already served, for a finite set of statically known types, by the type switch statement.

Upvotes: 1

Related Questions