首页 >后端开发 >Golang >为什么 fmt.Println 在传递基于值的对象时不调用我的 Stringer 接口的 String 方法?

为什么 fmt.Println 在传递基于值的对象时不调用我的 Stringer 接口的 String 方法?

Susan Sarandon
Susan Sarandon原创
2024-12-06 19:35:15493浏览

Why Doesn't fmt.Println Invoke My Stringer Interface's String Method When Passing a Value-Based Object?

Stringer 接口与 Println 的混淆:理解基于值与基于指针的对象

问题:

在对象实现了Stringer接口的场景下,为什么不如果对象是基于值的,那么使用 fmt.Println 时会调用对象的 String 方法吗?

代码示例:

考虑以下 Go 代码:

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)
}

当 myCar 是指针时,String 方法将按预期调用。但是,当 myCar 是一个值时,将使用默认的 Go 格式。

答案:

此行为的原因在于 Go 接口的工作方式。当您指定实现接口的类型(在本例中为 Stringer)时,Go 期望该类型是接口的确切类型。当您将Car类型的值传递给fmt.Println时,它会隐式转换为interface{},并且interface{}类型系统中没有Car类型。相反,它是 *Car 类型(指向 Car 的指针)。

fmt.Println 函数使用类型开关来确定如何根据其类型打印值。对于 Stringer 接口,它检查该值是否实现 String 方法。由于 Car(基于值)不实现 String,因此使用默认格式。但是,当您显式调用 myCar.String() 时,编译器会自动将其转换为 (&myCar).String(),它具有正确的 *Car 类型并调用所需的格式化方法。

以确保无论其类型如何,对象都会根据需要进行格式化,您有两个选择:

  1. 在汽车上实现字符串(基于值): 这需要为 Car 创建一个单独的 String 方法来操作值接收器,这会导致不必要的对象复制。
  2. 始终传递一个指向 fmt.Println 的指针: 通过使用 fmt.Println(&myCar),您可以确保传递的值具有正确的 *Car 类型,并且 String 方法将被调用为预计。

以上是为什么 fmt.Println 在传递基于值的对象时不调用我的 Stringer 接口的 String 方法?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn