在Go中,为什么我的Stringer接口方法不被调用?使用fmt.Println时 [英] In Go, why isn't my Stringer interface method getting invoked? When using fmt.Println

查看:190
本文介绍了在Go中,为什么我的Stringer接口方法不被调用?使用fmt.Println时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下代码:

  package main 

importfmt

类型Car结构{
年int
make字符串
}

func(c * Car)字符串()字符串{
返回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使用值方法,因为那意味着每次调用时都会复制该对象,这些接口不合理。我不想总是手动调用.String(),因为我试图让duck-typing系统做到这一点。



谢谢

-Ralph

解决方案当调用 fmt.Println myCar 隐式转换为类型接口{} 你可以从函数签名中看到。然后, fmt 包中的代码执行类型切换如何打印这个值,看起来像这样:

  switch v:= v。(type){
case string:
os.Stdout.WriteString(v)
case fmt.Stringer:
os.Stdout.WriteString(v.String())
// ...

然而, fmt.Stringer Car 没有实现字符串(因为它在 *车)。调用 String 手动工作是因为编译器发现 String 需要一个 * Car $ c>,并自动将 myCar.String()转换为(& myCar).String()。对于有关接口的任何事情,您必须手动完成。因此,您必须在 Car 上实现 String ,或者总是将指针传递给 fmt.Println

  fmt.Println(&myCar)


Suppose I have the following code:

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

When I call fmt.Println(myCar) and the object in question is a pointer, my String() method gets called properly. If, however the object is a value, my output is formatted using the default formatting built into Go and my code to format the said object is not called.

The interesting thing is in either case if I call myCar.String() manually it works properly whether my object is either a pointer or value.

How can I get my object formatted the way I want no matter if the object is value-based or pointer-based when used with Println?

I don't want to use a value method for String because then that means every time it's invoked the object is copied which seams unreasonable. And I don't want to have to always manually called .String() either because I'm trying to let the duck-typing system do it's work.

Thanks in advance!

-Ralph

解决方案

When calling fmt.Println, myCar is implicitly converted to a value of type interface{} as you can see from the function signature. The code from the fmt package then does a type switch to figure out how to print this value, looking something like this:

switch v := v.(type) {
case string:
    os.Stdout.WriteString(v)
case fmt.Stringer:
    os.Stdout.WriteString(v.String())
// ...
}

However, the fmt.Stringer case fails because Car doesn't implement String (as it is defined on *Car). Calling String manually works because the compiler sees that String needs a *Car and thus automatically converts myCar.String() to (&myCar).String(). For anything regarding interfaces, you have to do it manually. So you either have to implement String on Car or always pass a pointer to fmt.Println:

fmt.Println(&myCar)

这篇关于在Go中,为什么我的Stringer接口方法不被调用?使用fmt.Println时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆