我是Go的新手,我正在研究它的界面功能。
以下是代码:
package main
import (
"fmt"
"reflect"
)
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
func (a *Integer) Add(b Integer) {
*a += b
}
type LessAdder interface {
Less(b Integer) bool
Add(b Integer)
}
var a Integer = 1
var b LessAdder = &a
func main() {
fmt.Println(reflect.TypeOf(b))
fmt.Println(b.Less(2))
b.Add(a)
fmt.Println(a)
}
它将输出以下内容:
*main.Integer
true
2
嗯,这很好用。
要点是:
var b LessAdder = &a
的工作原理。指针自动取消引用是在这里发生,还是在b调用成员方法时?
输出*main.Integer
告诉我们b是指向Integer
类型的指针,因此它是第二种情况。
然后棘手的事情来了:
当我向代码添加fmt.Pringln(*b)
时,编译器会出现错误:
demo/demo1
./demo1.go:31: invalid indirect of b (type LessAdder)
这让我很困惑。 由于b
是Integer
的指针类型,因此取消引用它应该有效。但为什么不呢?
答案 0 :(得分:7)
你的最后一句:
&#34;由于
b
是Integer
的指针类型,因此取消引用它应该有效。&#34;
停在那儿。 b
不是指针类型的变量,因此您无法dereference它。
它是interface type的变量,它是一对值和一个类型(值,类型)的示意图,其中&a
为值,*Integer
为类型(博客)文章The Laws of Reflection,第The representation of an interface部分。)
这是指针类型变量*Integer
的声明:
var ip *Integer
这是一种接口类型:
var intf LessAdder
执行此操作时:
var b LessAdder = &a
接口值(类型为LessAdder
)是自动/隐式创建的,它将保存值&a
(以及类型*Integer
)。这是一个有效的操作,因为&a
的类型(*Integer
)实现了接口LessAdder
:*Integer
的{{3}}是接口的超集LessAdder
(在这种情况下它们是相同的,接口类型的方法集是它的接口)。
现在当你调用b.Less(2)
时,由于Less()
有一个值接收器,指针将被取消引用,并且指针值的副本将被制作并使用/传递为方法的值接收器Less()
。
fmt.Println(reflect.TypeOf(b))
并不谎言,但它会打印动态类型的b
。 b
的动态类型确实是*Integer
,但b
的静态类型是LessAdder
,而静态类型决定了你的能力使用值以及允许的操作符或方法。
答案 1 :(得分:1)
LessAdder
被声明为方法Less
和Add
的接口。由于Add
是使用*Integer
的接收方声明的,因此*Integer
可以是LessAdder
; Integer
不能。当您执行var b LessAdder = &a
时,它是指向a
的指针,该指针存储在界面b
中。
自动间接发生在调用b.Less(2)
时,因为*Integer
上的方法和Integer
上的方法都对*Integer
的方法集有贡献。
您无法使用*b
,因为虽然b
包含 *Integer
,但其静态类型为LessAdder
,而不是*Integer
}。撇开接口的表示,LessAdder
不是指针类型,*b
如果允许的话,根本就没有可表达的类型。
您可以使用type assertion再次访问b
Integer *
; b.(*Integer)
是*Integer
类型的表达式,*b.(*Integer)
是Integer
。如果b
中的值毕竟不是*Integer
,则这两种情况都会导致运行时出现混乱。