问题描述
????????在《Go语言编程》 里面讲接口赋值的时候,对对象实例赋值给接口做了如下案例 :
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
func (a *Intger) Add(b Integer) {
*a += b
}
// 定义接口
type LessAdder interface {
Less(b Integer) bool
Add(b Integer)
}
func main() {
var a Integer = 1
var b LessAdder = &a // (1)
}
???????? (1) 哪里说的是会自动生成一个新的方法
func (a *Integer) Less( b Integer) bool {
return (*a) < b
}
????????这样我们引申一下, 将Add
函数也修改如下
func (a Integer) Add(b Integer) {
a += b
}
// 赋值给接口
var a Integer = 1
var b LessAdder = &a // (2)
????????同理应该也会生成一个新的函数(如下代码):
func (a * Integer) Add(b Integer) {
(*a) += b
}
????????按新生成函数形式来看, 其调用应该会修改 a
指针的指向的值, 但如下代码结果依然是1, 请问这是为什么。
var a Integer = 1
var b LessAdder = &a
b.Add(100)
fmt.Println(a) // 1
###
不会生成一个新方法的。
Method sets
A type may have a method set associated with it. The method set of an interface type is its interface. The method set of any other type T
consists of all methods declared with receiver type T
. The method set of the corresponding pointer type *T
is the set of all methods declared with receiver *T
or T
(that is, it also contains the method set of T
). Further rules apply to structs containing embedded fields, as described in the section on struct types. Any other type has an empty method set. In a method set, each method must have a unique non-blank method name.
Receiver 是 T
的方法可以直接给 *T
用。
先说结论,Go 会判断值或指针作为方法的 caller 时,对应的方法集(method set)是否合法,但不会帮你“生成”新的方法,至少我没有从官网的文档里看到类似的说法。
楼上@fefe 已经说得很明确了,我这里只是补充一下。
首先,Go 判断接口是否被实现时会对 method set 进行判断。比如这样写的时候:
var a Integer = 1
var b LessAdder = a
如果 Integer
实现了下面的方法
func (a *Intger) Add(b Integer) {
*a += b
}
那么就会报错
cannot use a (type Integer) as type LessAdder in assignment:
Integer does not implement LessAdder (Add method has pointer receiver)
其次,Go 在调用方法的时候,会根据 method 的 receiver 类型对 caller 做一些“转换”,比如取值或者解引用。最后的代码中 a
的直没有改变是因为调用 Add
的时候 Go 帮你对b
进行了解引用,然后将(*b)
的值作为一个 value 类型的 caller 传递到 Add
里。这样说可能还是不太形象,结合官网对于 receiver 等价于形参的解释,实际上应该是这样的:Add(*b, 100)
.
所以 a
没有改变不是因为没有“生成”新方法,而是 Go 帮你做了一次值拷贝。
深究的话还是有很多不是确切知道的点,比如什么情况下会做 method set 的判断,以及什么情况下不会对 caller 取地址,等等。以上,我也是查查官网文档,如果有理解不对的地方请随时指出来。