Confused about implicitly dereferencing a pointer when assigning a pointer to an interface in Go

I am new to Go and I am learning its interface.

Here is the code:

package main

import (
        "fmt"
        "reflect"
)

type Integer int

func (a Integer) Less(b Integer) bool {
        return a < b
}

func (a *Integer) Add(b Integer) {
        *a += b
}

type LessAdder interface {
        Less(b Integer) bool
        Add(b Integer)
}

var a Integer = 1

var b LessAdder = &a

func main() {
        fmt.Println(reflect.TypeOf(b))
        fmt.Println(b.Less(2))
        b.Add(a)
        fmt.Println(a)

}

      

And it will output the following:

*main.Integer
true
2

      

Ok, this works really well.

Point: How it works var b LessAdder = &a

. Is there an automatic dereference of a pointer here or when b calls a member method?

The inference *main.Integer

tells us that b is a pointer to a type Integer

, hence this is the second case.

Then the tricky thing comes up: when I add fmt.Pringln(*b)

to the code, the compiler comes up with an error:

 demo/demo1
./demo1.go:31: invalid indirect of b (type LessAdder)

      

And that confuses me. Since it b

is a type of pointer to Integer

, dereferencing it should work. But why not?

+3


source to share


2 answers


Your last suggestion:

"Since it b

is a pointer type Integer

, dereferencing it should work."

Stop here. b

not a pointer type variable and therefore you cannot dereference it.

It is a type variable of a type that schematically represents a pair of values ​​and a type (value, type), holding &a

both a value and *Integer

a type (blog article
Laws of Reflection , section Interface Representation ).

This announcement pointer variable type *Integer

:

var ip *Integer

      

And this is one of the interface types:



var intf LessAdder

      

When you do this:

var b LessAdder = &a

      

What happens is that the interface (type LessAdder

) value is created automatically / implicitly, which will hold the value &a

(and type *Integer

). This is a valid operation, since the type &a

(which *Integer

) implements the interface LessAdder

: the set method *Integer

is a superset of the interface LessAdder

(in which case they are equal, the set of methods of the interface is its interface).

Now when you call b.Less(2)

since it Less()

has a value sink, the pointer will be dereferenced and a copy of the sharpened value will be made and used / passed as the method value sink Less()

.

fmt.Println(reflect.TypeOf(b))

does not lie, but it will print a dynamic type b

. The dynamic type is b

valid *Integer

, but the static type b

is equal LessAdder

, and the static type is what determines what you can do with the value and what operators or methods are allowed on it.

+7


source


LessAdder

is declared as an interface with methods Less

and Add

. Since it is Add

declared with the receiver *Integer

, a *Integer

may be LessAdder

; a Integer

cannot. When you do var b LessAdder = &a

, it is a pointer to a

that is stored in the interface b

.

Automatic indirection occurs on invocation b.Less(2)

because both methods on *Integer

and methods on Integer

contribute to the set of methods *Integer

.



You cannot use *b

because although a b

contains a *Integer

, statically it is of type LessAdder

and not *Integer

. Representation of interfaces aside, is LessAdder

not a pointer type and *b

, if allowed, will not have an expressed type at all.

You can use type assertion to access b

like Integer *

again; b.(*Integer)

is a type expression *Integer

, and *b.(*Integer)

- Integer

. Both of them will panic at runtime if the value is b

not *Integer

in the end.

+1


source







All Articles