Inkeliz
Inkeliz

Reputation: 1091

How to get a pointer of an interface

It's hard to explain, but how I can get a pointer of a something that implements some interface?


Consider the code below:

package main

import (
    "fmt"
    "unsafe"
)

type Interface interface {
    Example()
}

type StructThatImplementsInterface struct {
}

func (i *StructThatImplementsInterface) Example() {
}

type StructThatHasInterface struct {
    i Interface
}


func main() {
    sameInterface := &StructThatImplementsInterface{}

    struct1 := StructThatHasInterface{i: sameInterface}
    struct2 := StructThatHasInterface{i: sameInterface}

    TheProblemIsHere(&struct1)
    TheProblemIsHere(&struct2)

}

func TheProblemIsHere(s *StructThatHasInterface) {
    fmt.Printf("Pointer by Printf: %p \n", s.i)
    fmt.Printf("Pointer by Usafe: %v \n", unsafe.Pointer(&s.i))
}

https://play.golang.org/p/HoC5_BBeswA


The result will be:

Pointer by Printf: 0x40c138 
Pointer by Usafe: 0x40c140 
Pointer by Printf: 0x40c138 
Pointer by Usafe: 0x40c148 

Notice that the Printf gets the same value (because both StructThatHasInterface uses the same sameInterface). However, the unsafe.Pointer() returns distinct values.

How can I get the same result of Printf without use fmt, and reflect if possible?

Upvotes: 1

Views: 957

Answers (1)

Thundercat
Thundercat

Reputation: 120951

In the current version of Go, an interface value is two words long. The concrete value or a pointer to the concrete value is stored in the second word. Use the following code to get the second word as a uintptr:

  u := (*[2]uintptr)(unsafe.Pointer(&s.i))[1]

This code is unsafe and is not guaranteed to work in future.

The supported way to get the pointer is:

  u := reflect.ValueOf(s.i).Pointer()

Upvotes: 4

Related Questions