Created
July 19, 2015 02:51
-
-
Save samertm/59928bc579d8589c840b to your computer and use it in GitHub Desktop.
Surprising behavior for value types with pointer methods.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "fmt" | |
type T struct { | |
Thing string | |
} | |
func (t *T) Set(thing string) { | |
t.Thing = thing | |
} | |
func SetT(t *T, thing string) { | |
t.Thing = thing | |
} | |
type Setter interface { | |
Set(thing string) | |
} | |
func SetSetter(s Setter, thing string) { | |
s.Set(thing) | |
} | |
func main() { | |
// Surprising behavior for value types with pointer methods. | |
// | |
// Everyone knows that you can trivially call a method defined on a value | |
// (e.g. 'func (t T) SomeFunc() {}; pointerT := &T{}; t.SomeFunc()'). This | |
// is simple to explain conceptually: the pointer is copied and used in the | |
// body of the method as a value type. | |
// | |
// But did you know that you can call pointer methods on value types? | |
var t T = T{Thing: "HI"} // t is of type T (a value, not a pointer). | |
fmt.Println(t) // Prints "{HI}" | |
// SetT takes a pointer of T. We must give it t's address (&t) because t | |
// is a value type, not a pointer type. 'SetT(t, "BRO")' would error. | |
SetT(&t, "BRO") | |
fmt.Println(t) // Prints "{BRO}" | |
// Set is a method defined on the *pointer* T. Even though t is a value, | |
// not a pointer, THIS IS STILL VALID AND IT MODIFIED t. WTF?? | |
t.Set("YO") | |
fmt.Println(t) // Prints "{YO}" | |
// MORAL OF THE STORY: No matter whether you define a variable as a value | |
// or a pointer, you can still call pointer methods on it and modify your | |
// variable. | |
// | |
// This basically turns all types into reference types (like Java) when | |
// methods are called on them. | |
// BONUS: For interfaces, pointer types have all of the methods defined on | |
// pointers and values for a type, but value types only have the methods | |
// defined on values for a type. | |
// SetSetter(t, "HELLO") // -> error! T does not implement Setter (Set method has pointer receiver) | |
SetSetter(&t, "HI THERE") // Totally fine. | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment