Consider the following code. The first function is a receiver method for type MessageStr. Why fmt.Println(msgstr)
executes the first method without calling the method as fmt.Println(msgstr.String())
. Also why fmt.Println(msgint32)
doesn't execute the second method.
package main
import (
"fmt"
)
type MessageStr string
type MessageInt32 int32
func (msgs MessageStr) String() string {
return string("<<" + msgs + ">>")
}
func (msgi MessageInt32) Int32() int32 {
return int32(msgi * 2)
}
func main() {
msgstr := MessageStr("Mastering Go")
// why this outputs <<Mastering Go>>
// without calling the String() method
fmt.Println(msgstr)
msgint32 := MessageInt32(11)
// why this doesn't output 11*2 = 22
fmt.Println(msgint32)
fmt.Println(msgint32.Int32())
}
When you call fmt.Println
, it expects an object that implements the Stringer
interface. It's documented as follows:
If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any)
The fmt
package also declares the Stringer
interface:
type Stringer interface {
String() string
}
Such objects must have a String()
method that takes no arguments and returns a string
. fmt.Println
then invokes the String
method. This lets us define for custom types how they're going to be printed out. For example:
package main
import "fmt"
type Person struct {
name string
age int
}
func (p Person) String() string {
return fmt.Sprintf("%s<%d>", p.name, p.age)
}
func main() {
p := Person{name: "Joe", age: 39}
fmt.Println(p)
}
Will print out:
Joe<39>
Because we've customized the way Person
objects are turned into strings. More details:
If you're interested in the mechanics of how this actually happens in the fmt
package, take a look at the handleMethods
method in src/fmt/print.go
.