【问题标题】:The difference between t and *tt 和 *t 的区别
【发布时间】:2017-08-21 07:24:33
【问题描述】:
package main

import "fmt"

type TT struct {
    a int
    b float32
    c string
}

func (t *TT) String() string {
    return fmt.Sprintf("%+v", *t)
}

func main() {
    tt := &TT{3, 4, "5"}
    fmt.Printf(tt.String())
}

代码可以正常工作。但是如果我如下更改String 方法,就会导致死循环。不同之处在于*t 被替换为t。为什么?

func (t *TT) String() string {
    return fmt.Sprintf("%+v", t)
}

【问题讨论】:

    标签: string pointers go methods stack-overflow


    【解决方案1】:

    因为fmt 包检查被打印的值是否有String() string 方法(或者换句话说:如果它实现了fmt.Stringer 接口),如果是,它将被调用以获取@987654332 @值的表示。

    这在fmt 包文档中有记录:

    [...] 如果操作数实现方法 String() 字符串,则将调用该方法将对象转换为字符串,然后根据动词(如果有)的要求对其进行格式化。

    这里:

    return fmt.Sprintf("%+v", *t)
    

    您将*t 类型的TT 值传递给fmt 包。如果TT.String()方法有一个指针接收器,那么TT类型的method set不包括String()方法,所以fmt包不会调用它(只有*TT的方法集包含)。

    如果你把接收器改成非指针类型,那么TT类型的方法集将包含String()方法,所以fmt包会调用它,但是这是我们目前使用的方法,所以这是一个无休止的“间接递归”。

    预防/保护

    如果由于某种原因您确实需要使用与传递给 fmt 包的值的类型相同的接收器类型,避免这种情况/保护它的一种简单而常见的方法是创建一个新类型type 关键字,并在传递的值上使用 conversion 类型:

    func (t TT) String() string {
        type TT2 TT
        return fmt.Sprintf("%+v", TT2(t))
    }
    

    Go Playground 上试试这个。

    但是为什么会这样呢?因为type 关键字创建了一个新类型,而新类型将有 个方法(它不会“继承”底层类型的方法)。

    这会产生一些运行时开销吗?编号引用自Spec: Type declarations

    特定规则适用于数字类型之间或字符串类型之间的(非常量)转换。这些转换可能会更改x 的表示并产生运行时成本。 所有其他转换仅更改x 的类型而不是表示。

    在此处了解更多信息:Does convertion between alias types in Go create copies?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-15
      • 2021-03-30
      • 2012-03-10
      • 1970-01-01
      • 1970-01-01
      • 2016-09-07
      • 1970-01-01
      相关资源
      最近更新 更多