小编典典

为什么我的Stringer接口方法没有被调用?使用fmt.Println时

go

假设我有以下代码:

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(),因为我正试图让鸭子键入系统来工作。


阅读 250

收藏
2020-07-02

共1个答案

小编典典

从函数签名可以看到,调用时fmt.PrintlnmyCar将隐式转换为type的值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()。对于任何有关接口的内容,您都必须手动进行。因此,您要么必须实现StringCar要么总是将指针传递给fmt.Println

fmt.Println(&myCar)
2020-07-02