英文:
Why reference type can be assigned to not satisfied interface [golang]
问题
我发现值类型和引用类型之间的接口可满足性令人困惑。我仍然无法弄清楚在Go语言中它是如何工作的。考虑下面这段程序:
type Counter1 int
type Counter2 int
func (c Counter1) String() string {
}
func (c *Counter2) String() string {
}
func main() {
var c1 Counter1
var c2 Counter2
var i1 fmt.Stringer = &c1 // 赋值语句 1
var i2 fmt.Stringer = c2 // 赋值语句 2
}
然而,赋值语句 1 能够正常工作,但赋值语句 2 却不能。我本来预期两者都不能工作:类型 Counter1
满足 fmt.Stringer
接口,但 *Counter1
类型不满足该接口。因此,&c1
不应该赋值给 i1
;类型 Counter2
不满足 fmt.Stringer
接口,但 *Counter2
类型满足该接口,所以 c2
不应该赋值给 i2
,实际上也确实不能。这个测试程序的结果对我来说没有意义。我原以为这可能是一种语法糖,Go编译器会自动在引用类型和值类型之间进行转换。然而,下面这段测试代码让我更加困惑:
type Test interface {
f()
g()
}
func (c Counter1) f() {
}
func (c *Counter1) g() {
}
func receiveTest(t Test) {
}
func main() {
......
var c3 Counter1
var p3 Test = &c3 // 能够工作
receiveTest(&c3) // 能够工作
receiveTest(c3) // 不能工作
}
既不是 *Counter1
类型,也不是 Counter1
类型满足 Test
接口。然而,第一和第二个赋值语句仍然能够正常工作。这对我来说没有意义。
英文:
I find interface satisfiability between value type and reference type confusing. I still cannot figure out how it works in golang. Consider this piece of program:
type Counter1 int
type Counter2 int
func (c Counter1) String() string {
}
func (c *Counter2) String() string {
}
func main() {
var c1 Counter1
var c2 Counter2
var i1 fmt.Stringer = &c1 // assignment 1
var i2 fmt.Stringer = c2 // assignment 2
}
However assignment 1 works but assignment 2 doesn't. I expected none of them works: Type Counter1 satisfies fmt.Stringer however type *Counter1 doesn't. So &c1 should not be assignable to i1; Type Counter2 doesn't satisfy fmt.Stringer however type *Counter2 does, so c2 should not be assignable to i2 and actually it cannot. The outcome of this test program doesn't make sense to me. I thought it might be some kind of syntactic sugar where go compiler converts between reference type and value type automatically. However the following piece of test code makes me more confused:
type Test interface {
f()
g()
}
func (c Counter1) f() {
}
func (c *Counter1) g() {
}
func receiveTest(t Test) {
}
func main() {
......
var c3 Counter1
var p3 Test = &c3 // works
receiveTest(&c3) // works
receiveTest(c3) // doesn't work
}
Neither type *Counter1 nor type Counter1 satisfies interface Test. However first and second assignment still works. It doesn't make sense to me.
答案1
得分: 3
在Go语言中,选择器表达式(x.f
)表示值x
(有时是*x
)的字段或方法f
。
基本上,在Go语言中,如果一个方法有一个指针接收器,你不需要写&object.method()
,而是可以直接写object.method()
。
因为在Go语言中接口是隐式的,只要对象本身不是指针,那么无论满足接口的方法是否有指针接收器,它们都可以用来满足接口。
所以,在你的例子中,Counter1
结构体可以调用f()
和g()
方法,但*Counter1
只能调用g()
方法。
英文:
> In Go, a selector expression (x.f
) denotes the field or method f
of the value x
(or sometimes *x
).
Basically, in Go, if you have a pointer receiver on a method, you do not have to write &object.method()
, but you can just write object.method()
https://play.golang.org/p/nh8X-vwdfr
https://play.golang.org/p/1uKwZw6E-J
Because interfaces are implicit in Go, as long as the object itself is not a pointer, then it doesn't matter if the methods that satisfy the interface have pointer receivers or not, they will still be used to satisfy it.
So, in your example, a Counter1
struct can have both f()
and g()
methods called on it, but a *Counter1
can only have a g()
method called on it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论