Interface behavior confuses me

I am new to go.

1

package main

import (
	"fmt"
)

type I interface {
	M()
}

type T struct {
	S string
}

func (t T) M() {
	fmt.Println(t.S)
}

func main() {
	var i I
	i = T{"Hello"}
	describe(i)
	i.M()
}

func describe(i I) {
	fmt.Printf("(%v, %T)\n", i, i)
}
({Hello}, main.T)
Hello

Program exited.

2

package main

import (
	"fmt"
)

type I interface {
	M()
}

type T struct {
	S string
}

func (t T) M() {
	fmt.Println(t.S)
}

func main() {
	var i I
	i = &T{"Hello"}
	describe(i)
	i.M()
}

func describe(i I) {
	fmt.Printf("(%v, %T)\n", i, i)
}
(&{Hello}, *main.T)
Hello

Program exited.

3

package main

import (
	"fmt"
)

type I interface {
	M()
}

type T struct {
	S string
}

func (t *T) M() {
	fmt.Println(t.S)
}

func main() {
	var i I
	i = &T{"Hello"}
	describe(i)
	i.M()
}

func describe(i I) {
	fmt.Printf("(%v, %T)\n", i, i)
}
(&{Hello}, *main.T)
Hello

Program exited.

4

package main

import (
	"fmt"
)

type I interface {
	M()
}

type T struct {
	S string
}

func (t *T) M() {
	fmt.Println(t.S)
}

func main() {
	var i I
	i = T{"Hello"}
	describe(i)
	i.M()
}

func describe(i I) {
	fmt.Printf("(%v, %T)\n", i, i)
}
# example
./prog.go:21:6: cannot use T{…} (value of type T) as type I in assignment:
	T does not implement I (M method has pointer receiver)

Go build failed.

So why did code 2 pass compile!!!
Methods and pointer indirection?
If code 4 fail compile code 2 also should fail compile?
What happen?

If T implements the interface I, then pointers to T will get dereferenced automatically, as this is a safe thing to do.

Though automatically referencing it is not safe, as it might introduce mutation where you do not expect it. Therefore, if only the pointer implements the interface, you need to manually reference to make you aware of the potential mutation that might happen.

1 Like

Thank you for your answer.

“Though automatically referencing it is not safe, as it might introduce mutation where you do not expect it.” is your reason. But if I did not use interfaces, it seem to me the compiler automatically references it like below code.

package main

import (
	"fmt"
)

type I interface {
	M()
}

type T struct {
	S string
}

func (t *T) M() {
	fmt.Println(t.S)
}

func main() {
	var i T
	i = T{"Hello"}
	describe(i)
	i.M()
}

func describe(i T) {
	fmt.Printf("(%v, %T)\n", i, i)
}
({Hello}, main.T)
Hello

Program exited.

i.M() as (&i).M()
Is it automatically referencing and not safe? Why only with interfaces is automatically referencing not work?

I had not expected this to work…

Oh…

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.