假设我有以下代码:
package main import "fmt" type Car struct{ year int make string } func (c *Car)String() string{ return fmt.Sprintf("{make:%s, year:%d}", c.make, c.year) } func main() { myCar := Car{year:1996, make:"Toyota"} fmt.Println(myCar) }
当我调用fmt.Println(myCar)且有问题的对象是指针时,我的String()方法将被正确调用。如果该对象是一个值,则使用Go内置的默认格式对我的输出进行格式化,而不会调用用于格式化该对象的代码。
有趣的是,无论哪种情况,如果我手动调用myCar.String(),无论我的对象是指针还是值,它都能正常工作。
与Println一起使用时,无论对象是基于值还是基于指针,如何以所需的方式格式化对象?
我不想为String使用value方法,因为那样就意味着每次调用它时,都会复制该对象,从而造成不合理的连接。而且我也不想总是手动调用.String(),因为我正试图让鸭子键入系统来工作。
从函数签名可以看到,调用时fmt.Println,myCar将隐式转换为type的值interface{}。fmt包中的代码然后进行类型切换以弄清楚如何打印此值,如下所示:
fmt.Println
myCar
interface{}
fmt
switch v := v.(type) { case string: os.Stdout.WriteString(v) case fmt.Stringer: os.Stdout.WriteString(v.String()) // ... }
但是,该fmt.Stringer案例失败了,因为Car未实现String(如上定义*Car)。String手动调用有效,因为编译器认为String需要a *Car,因此会自动转换myCar.String()为(&myCar).String()。对于任何有关接口的内容,您都必须手动进行。因此,您要么必须实现String,Car要么总是将指针传递给fmt.Println:
fmt.Stringer
Car
String
*Car
myCar.String()
(&myCar).String()
fmt.Println(&myCar)