- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
The Go FAQ answers a question关于方法中按值与按指针接收器定义的选择。该答案中的陈述之一是:
If some of the methods of the type must have pointer receivers, the rest should too, so the method set is consistent regardless of how the type is used.
这意味着,如果我对一种数据类型有一些改变数据的方法,因此需要按指针接收器,我应该对为该数据类型定义的所有方法使用按指针接收器。
另一方面,“fmt”
包调用 String()
方法,如 Stringer
接口(interface)中定义的那样 值(value)。如果使用接收器指针定义 String()
方法,则当相关数据类型作为参数提供给 fmt.Println
(或其他fmt
格式化方法)。这让我们别无选择,只能通过值接收者实现 String()
方法。
在满足 Stringer
接口(interface)的 fmt
要求的同时,如何才能像 FAQ 所建议的那样与按值还是按指针的选择保持一致?
编辑:
为了强调我提到的问题的本质,考虑这样一种情况,其中一个数据类型具有一组用按值接收者定义的方法(包括 String())。然后有人希望添加一个附加方法来改变该数据类型 - 所以他用接收器指针定义它,并且(为了保持一致,每个常见问题解答)他还更新了该数据类型的所有其他方法以使用-指针接收器。此更改对使用此数据类型的方法的任何代码的影响为零 - 但调用 fmt
格式化函数(现在需要传递指向变量的指针而不是其值,就像更改之前一样).因此,一致性要求仅在 fmt
的上下文中存在问题。需要根据接收者类型调整向 fmt.Println
(或类似函数)提供变量的方式,这打破了轻松重构包的能力。
最佳答案
如果您使用指针接收器定义您的方法,那么您应该使用和传递指针值,而不是非指针值。这样做传递的值确实实现了 Stringer
,fmt
包将没有问题“检测”并调用您的 String()
方法。
例子:
type Person struct {
Name string
}
func (p *Person) String() string {
return fmt.Sprintf("Person[%s]", p.Name)
}
func main() {
p := &Person{Name: "Bob"}
fmt.Println(p)
}
输出(在 Go Playground 上尝试):
Person[Bob]
如果您将 Person
类型的值传递给 fmt.Println()
而不是 *Person
类型的指针,是的,实际上 Person.String()
不会被调用。但是如果 Person
的所有方法都有指针接收者,那是一个强烈的指示你应该使用类型和它的值作为指针(除非你不打算将它的方法使用)。
是的,您必须知道您是否必须使用Person
或*Person
。处理它。如果你想编写正确高效的程序,你必须知道的不仅仅是使用指针值还是非指针值,我不知道为什么这对你来说很重要。如果您不知道,请查找它,如果您很懒惰,请使用指针作为指针值(的类型)的方法集,其中包含具有指针和非指针接收器的方法。
此外,Person
的作者可能会为您提供一个 NewPerson()
工厂函数,您可以依靠它返回正确类型的值(例如 Person
如果方法有值接收者,*Person
如果方法有指针接收者),所以你不必知道要使用哪个。
稍后将带有指针接收器的方法添加到以前只有带有值接收器的方法的类型的答案:
是的,正如您在问题中所述,这可能不会破坏现有代码,但继续使用非指针值可能不会从后来添加的带有指针接收器的方法中获益。
我们可能会问:这是一个问题吗?使用该类型时,您刚刚添加的新方法不存在。所以原始代码没有假设它的存在。所以这应该不是问题。
第二个考虑因素:该类型只有具有值接收者的方法,因此可以很容易地假设通过使用它们,值是不可变的,因为具有值接收者的方法不能改变值。使用该类型的代码可能以此为基础,假设它没有被其方法更改,因此从多个 goroutines 中使用它可能会正确地省略某些同步。
所以我确实认为,将带有指针接收器的新方法添加到以前只有带有值接收器的方法的类型不应该是“不透明的”,添加此新方法的人有责任修改此类型的使用“切换”到指针并确保代码保持安全和正确,或者处理非指针值将没有这种新方法的事实。
提示:
如果将来某个类型有可能具有增变器方法,您应该开始使用带有指针接收器的方法来创建它。这样做可以避免以后必须经历上述过程。
另一个技巧可能是完全隐藏类型,只发布接口(interface)。这样做,这种类型的用户不必知道接口(interface)是否包装了指针,这无关紧要。他们接收一个接口(interface)值,然后调用接口(interface)的方法。包作者有责任处理适当的方法接收器,并返回实现接口(interface)的适当类型。客户看不到这一点,他们不依赖于此。他们所看到和使用的只是界面。
关于go - Stringer 方法需要值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48296826/
Go 新手,所以请多多包涵。 我一直在查看“围棋之旅”页面,无意中发现了一些关于 Stringer 的令人费解的东西。考虑 https://tour.golang.org/methods/18 处的练
The Go FAQ answers a question关于方法中按值与按指针接收器定义的选择。该答案中的陈述之一是: If some of the methods of the type must
对于 Go 之旅中的 Stringers 练习:对于两种不同格式的打印,我得到了两种不同的输出。我唯一改变的是格式动词。他们是 %v 和 %d。理论上,它们会给出相同的输出。但是输出的顺序也改变了,这
我正在尝试使用 go generate/stringer (golang.org/x/tools/cmd/stringer) 在枚举上生成 String() 方法。我有问题,我认为是因为不同系统上的
知道如何修复下面的错误吗?我有一个 go 生成器 (stringer),我尝试运行它,但它一直报告说它找不到包导入,尽管包肯定是导入的。 stringer: checking package: mai
这个问题在这里已经有了答案: Can I type assert a slice of interface values? (2 个答案) 关闭 3 年前。 我有一个实现 stringer 接口(i
这个问题在这里已经有了答案: Why isn't my Stringer interface method getting invoked? When using fmt.Println (6 个答
我需要以这种格式将数据发送到数据库 - {"param1":"value1", "param2":"value2", "param3": {"username": "admin", "password
我正在完成 golang 之旅,但我被困在其中一个练习中。我不确定为什么以下内容不适用于 String() 函数: type IPAddr [4]byte func (addr IPAddr) Str
与 fmt.Stringer 一样, fmt 包寻找 error interface打印值时。如果一个type满足这两个接口(interface),fmt 仅在查找 error 而不是 Stringe
我可以实现 Stringer 来指定 fmt.Print() 如何将我的自定义类型写入字符串。 json marshal 有等效项吗? 我想在 go 中存储唯一值,并在 json 中将其表示为一个 s
这个问题在这里已经有了答案: puzzling behavior for Stringers? (2 个答案) 关闭 4 年前。 全部: 只是一个简单的问题: 围棋教程中 https://tour.
我有一个这样的结构: .foo/bar/constants.go .foo/constants.go .main.go 在 main.go 中声明类型: package agepack type Ev
我正在尝试使用 stringer cmd 以便我可以为某些 int 类型生成 String() 方法。这是代码的样子 //go:generate stringer -type=MyIntType ty
我想重写所有实例 sql.NullString 的 Stringer 接口(interface),以便实例的输出是 instance.String 而不是 { instance.String, ins
刚接触 Golang。所以我在 Go 之旅中读到了关于 stringer 的内容,我想知道是否有任何方法可以为任何类型的 slice 定义一个通用的自定义 Stringer()?例如: package
package main type foo struct { bar string baz string } func (f foo) String() string { re
假设我有以下代码: package main import "fmt" type Car struct{ year int make string } func (c *Car)Str
我是一名优秀的程序员,十分优秀!