Go 为什么接口分配比方法调用更严格?
我正在经历围棋之旅。我了解到,如果我们有一个接受指针作为接收器的方法,它也会接受值类型作为接收器(go会自动进行转换) 那么下面的代码是有效的,不管顶点是通过值还是指针接收的Go 为什么接口分配比方法调用更严格?,go,interface,Go,Interface,我正在经历围棋之旅。我了解到,如果我们有一个接受指针作为接收器的方法,它也会接受值类型作为接收器(go会自动进行转换) 那么下面的代码是有效的,不管顶点是通过值还是指针接收的 v := Vertex{1, 2} fmt.Println(v.Abs()) p := &v fmt.Println(p.Abs()) 但是,假设我们有以下接口: type Abser interface { Abs() float64 } 那么,为什么下面的代码无效 var a Abser v :=
v := Vertex{1, 2}
fmt.Println(v.Abs())
p := &v
fmt.Println(p.Abs())
但是,假设我们有以下接口:
type Abser interface {
Abs() float64
}
那么,为什么下面的代码无效
var a Abser
v := Vertex{1, 2}
a = v // invalid
我的理解是这样就可以了。尽管v是一种值类型,它“实现”了接受指针接收器的Abs函数,但它也会按值接受它
接口的设计是否只是为了更严格地规定接口变量在右侧所能容纳的内容?接口将*Vertex和Vertex视为两种不同的类型,但是Abs()方法也没有处理问题。在这两种情况下,Go都需要一个指针来运行该方法。最大的区别是,方法调用将自动采用
v
的地址,但检查是否有东西实现了接口则不会
方法调用:
在普通类型上使用指针接收器调用方法时,如果允许,Go将自动获取地址。来自(亮点是我的):
如果方法集(类型)为x,则方法调用x.m()有效
包含m,参数列表可以指定给参数列表
m如果x是可寻址的,并且&x的方法集包含m,则x.m()是
(&x).m()的简写形式
在这种情况下,x
引用变量v
,并且是。因此,在方法调用时,Go会自动运行(&v).Abs()
任务:
当尝试a=v
时,必须填写的检查是T是一种接口类型,x实现了T。
v
仅当其与接口匹配时才实现Abser
。该方法集的确定如下:
任何其他类型T的方法集由声明的所有方法组成
接收器类型为T。对应指针类型的方法集
*T是用receiver*T或T声明的所有方法的集合(也就是说,它还包含方法集合T)
您会注意到,在计算方法集时,Go不像在方法调用中那样使用v
的地址这意味着为var v Vertex
设置的方法为空,无法实现接口。
解决方案:
解决这一问题的方法是自己填写v
的地址:
var a Abser
v:=顶点{1,2}
a=&v
通过这样做,您现在看到的是*Vertex
的方法集,它确实包含Abs()float64
,因此实现了接口Abser
围棋之旅是学习该语言的资源,但是如果您发现了一些您认为奇怪的东西:阅读语言规范!该规范非常简短(比典型的语言规范短一个数量级),并且令人惊讶地可以理解。它解释了相关概念,如“可分配性”(即在何种条件下x=y
有效或无效),如何计算“方法集”,以及在何种情况下Go将自动取消引用或自动获取地址。读一下。
var a Abser
v := Vertex{1, 2}
a = v // invalid