Golang中默认String()函数的使用问题
Golang中默认String()函数的使用问题 我定义了一个结构体,我们称之为 S。仅仅通过这样做,我就创建了无限的数据类型:S、指向 S 的指针、指向 S 指针的指针,等等。
在这一系列无限的数据类型中,只有其中一个已经实现了默认的 String() 函数,那就是 S。<- 这是真的吗? (1)
因为 S 已经有一个默认的 String() 方法,如果我为 *S(指向 S 类型的指针)定义一个 String() 方法,这将有一个缺点:当为 *S 调用时它可以工作,但不会为 S(非指针)调用。当为 S(常规类型,非指针)调用时,默认的 String() 方法仍然会被调用。<- 这是真的吗?
这就是为什么,在创建自定义的 String() 函数时,将其接收器设为类型 S 而不是指向 S 的指针是有益的。因为 *S 没有默认的 String() 函数,当在指针接收器上调用 String() 时,我的自定义 String()(为 S 定义,非指针)会被调用。<- 这是真的吗?
对于类型 **S(指向 S 指针的指针),我为 S 编写的自定义 String() 函数不会被调用。<- 为什么会这样,这与陈述 (1) 相矛盾。
请帮我弄清楚真相,希望这个真相能让我摆脱疑虑 🙂 也可以看看这个例子:https://play.golang.org/p/tQ_nfRHk8w4
更多关于Golang中默认String()函数的使用问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,String()方法遵循接收者类型的方法集规则。让我们逐一分析你的问题:
-
关于默认
String()方法的存在: 只有S类型有默认的String()方法(通过实现fmt.Stringer接口),而*S、**S等指针类型没有默认实现。这是正确的。 -
为
*S定义String()方法的影响: 如果你只为*S定义String()方法,那么:*S类型会调用你定义的方法S类型仍然调用默认的String()方法 这是因为方法集规则:非指针类型S的方法集只包含值接收者的方法,而指针类型*S的方法集包含所有值接收者和指针接收者的方法。
-
为
S定义String()方法的好处: 如果你为S(值接收者)定义String()方法:S类型会调用你的自定义方法*S类型也会调用你的自定义方法(通过Go的自动解引用) 这是正确的,因为指针类型可以自动调用值接收者的方法。
-
关于
**S类型: 对于**S类型,你为S定义的String()方法不会被调用,这与第一条陈述并不矛盾。原因如下:
package main
import "fmt"
type S struct {
value int
}
// 为S定义String()方法(值接收者)
func (s S) String() string {
return fmt.Sprintf("S{value: %d}", s.value)
}
func main() {
s := S{value: 42}
ps := &s
pps := &ps
fmt.Println("s:", s) // 调用S.String()
fmt.Println("ps:", ps) // 调用S.String()(自动解引用)
fmt.Println("pps:", pps) // 不会调用S.String()
// 明确调用String()方法
fmt.Println("s.String():", s.String())
fmt.Println("ps.String():", ps.String())
// fmt.Println("pps.String():", pps.String()) // 编译错误:pps没有String()方法
}
关键点解释:
**S类型的方法集是空的,因为它不是S或*S- Go的方法调用只自动解引用一层指针
**S无法自动转换为*S来调用方法
更完整的示例:
package main
import "fmt"
type S struct {
value int
}
// 为*S定义String()方法
func (s *S) String() string {
if s == nil {
return "nil"
}
return fmt.Sprintf("*S{value: %d}", s.value)
}
func main() {
s := S{value: 42}
ps := &s
pps := &ps
fmt.Println("s:", s) // 使用默认String()方法
fmt.Println("ps:", ps) // 调用*S.String()
fmt.Println("pps:", pps) // 不会调用任何String()方法
// 类型断言示例
var stringer fmt.Stringer
stringer = ps // 成功:*S实现了Stringer
// stringer = pps // 失败:**S没有实现Stringer
fmt.Println("stringer:", stringer)
}
总结:
- 只有
S类型有默认的String()方法 - 为
S定义String()方法是最佳实践,因为它对S和*S都有效 **S及更深层的指针不会自动调用S的方法,因为它们的方法集不同- 方法调用只自动解引用一层指针


