0

I can't find anything about *interface{} on google. So... The question is why these two approaches work differently?

package main

type MyStruct struct {}

func valI(x interface{}) {}
func pointI(x *interface{}) {}

func valS(s MyStruct) {}
func pointS(s *MyStruct) {}

func main() {
    s := MyStruct{}
    p := &s

    valI(s)
    valI(p) // Why? Success
    pointI(s) // Why?  Fail: cannot use s (type S) as type *interface {} in argument to point: *interface {} is pointer to interface, not interface
    pointI(p) // Why?  Fail: cannot use p (type *S) as type *interface {} in argument to point: *interface {} is pointer to interface, not interface

    valS(s)
    valS(p) // It's obvious to me why these two fail
    pointS(s) // -//-
    pointS(p)
}

Playground: https://play.golang.org/p/pio5vf-fBxH

2
  • I don't know if it's right to say that interfaces ARE pointers, but they certainly behave like it. Commented Jun 18, 2020 at 16:50
  • From golang.org/doc/faq#pointer_to_interface: "When should I use a pointer to an interface? Almost never." That is all to know. Pointer to interface is wrong in almost all cases. You really never need this (except when you are an expert and then it will be obvious why and how.) Commented Jun 18, 2020 at 19:46

1 Answer 1

3

An interface contains a pointer to the underlying data and type information. When you assign a non-interface value to an interface (or pass a non-interface value as an interface arg) the compiler generates code to pass the type and pointer to the underlying data. In a way, an interface is a struct:

type interface struct {
   Data pointer
   Type type
}

A pointer to an interface is simply a pointer to an instance of this struct.

All values satisfy the interface{} interface, so you can pass a struct or *struct where interface{} is required. *interface{} is a pointer to an interface, and only a pointer to an interface can be passed:

x:=interface{}(s)
pointI(&x)
Sign up to request clarification or add additional context in comments.

6 Comments

It's even more confusing now: fmt.Println( reflect.TypeOf(x), reflect.TypeOf(s)) // main.MyStruct main.MyStruct
TypeOf returns the concrete type of the passed value. TypeOf will not return an interface.
@Stanislav Use reflect.TypeOf(&x).Elem() to get the type of x.
@Stanislav note that TypeOf gets an interface{} argument, and it simply returns the type part of that arg. When you pass s, compiler constructs an interface containing the type of s. When you pass x, it is already an interface (containing s as its type), so it passes that directly. So for both cases, you get MyStruct.
Ok, I think I get the point. There is no difference between an empty interface and actual user-defined interfaces (like "MyInterface") in my example. I should look into interface pointers, not "interface{}" pointers. Ok, thanks
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.