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?
source to share
Your last suggestion:
"Since it
b
is a pointer typeInteger
, 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.
source to share
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.
source to share