【发布时间】:2018-01-17 08:40:19
【问题描述】:
The Go FAQ answers a question 关于方法中按值与按指针接收器定义的选择。该答案中的陈述之一是:
如果该类型的某些方法必须有指针接收器,其余的也应该有,因此无论该类型如何使用,方法集都是一致的。
这意味着如果我有一些数据类型的方法可以改变数据,因此需要按指针接收器,我应该对为该数据类型定义的所有方法使用按指针接收器。
另一方面,"fmt" 包调用String() 方法,如Stringer 接口按值 中定义的那样。如果使用接收器按指针定义String() 方法,则当关联数据类型作为fmt.Println(或其他fmt 格式化方法)的参数时,它不会被调用。这使得人们别无选择,只能通过值接收器来实现String() 方法。
在满足Stringer 接口的fmt 要求的同时,如何才能与常见问题解答所建议的按值与按指针的选择保持一致?
编辑:
为了强调我提到的问题的本质,考虑这样一种情况,其中一个数据类型具有一组由接收者按值定义的方法(包括 String())。然后,一个人希望添加一种改变该数据类型的附加方法 - 所以他用接收器按指针定义它,并且(为了保持一致,根据常见问题解答)他还更新了该数据类型的所有其他方法以供使用-指针接收器。此更改对使用此数据类型方法的任何代码的影响为零 - 但用于调用 fmt 格式化函数(现在需要传递指向变量的指针而不是其值,与更改之前一样)。所以一致性要求只有在fmt 的上下文中才有问题。需要根据接收者类型调整向fmt.Println(或类似函数)提供变量的方式,这破坏了轻松重构包的能力。
【问题讨论】:
-
请注意,这是常见问题解答而不是规范,规范允许单一类型的混合接收器(值/指针),如果方法 A 在指针上而 B 在上,您的程序仍将编译一个值。另外should和must是不一样的,我个人认为FAQ中的陈述是一般性的建议,而不是盲目遵循的东西。你有一个没有意义的案例吗?那就不要坚持了!
-
哇!您发现以后的代码更改可能会产生意想不到的结果!欢迎来到俱乐部。测试。
-
@mkopriva ,我的问题是关于核心包“fmt”的常见问题解答一致性,它需要按值接收器(假设希望以“自然”方式使用“fmt”方法来提供变量本身,而不是它们的引用/指针)。正如您所建议的,在这种情况下我需要忽略常见问题解答,但我想问,如果在核心包的上下文中不能遵守这种方法,为什么常见问题解答会说明这种方法?
-
@ElazarR 首先,
fmt包不需要按值 afaik;第二,“自然”? “自然”是谁的意见?如果一个变量已经是一个指针,那么这个*v是否比这个v更“自然”?无论如何,FAQ 陈述了一个一般性建议,这取决于 Go 语言的用户,核心包与否,他们是否遵守建议。就使用fmt而言,客户端库可以很容易地遵守它,您的情况可能会有所不同,但这并不意味着“它不能被遵守”。 -
@ElazarR 添加该方法不会破坏任何内容。更换接收器即可。最好的建议是:停止担心现实生活中的非问题。