为什么不按名称调用此String()方法

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.