英文:
Assign struct pointer to interface pointer
问题
我正在尝试重构一些 Golang 源代码,并且想使用接口,但我遇到了很大的困难(请原谅,我是一个彻头彻尾的 C/C++ 孤儿)。
我提取了一个小样例来展示我遇到的错误:
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m MyProcessor) Init() int {
return m.a
}
func main() {
t := &(MyProcessor{2})
var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
fmt.Println((*t).Init(), (*p).Init())
}
为什么第二个赋值会失败?
以下是修改后的代码,用于演示我想要做的事情。我以为接口更类似于 C++ 的类,这是我的错误。我还在学习中。
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m *MyProcessor) Init() int {
m.a++
return m.a
}
func main() {
t := &(MyProcessor{2})
m := MyProcessor{4}
var p LogProcessor = &m
fmt.Println(t.Init(), p.Init())
fmt.Println(t.a, m.a)
}
英文:
I'm trying to refactor some golang source code, and I would like to use interfaces but I find huge difficulties (bear with me, I'm a hard-core C/C++ orphan)
I extracted a small sample exhibiting the error I get
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m MyProcessor) Init() int {
return m.a
}
func main() {
t := &(MyProcessor{2})
var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
fmt.Println((*t).Init(), (*p).Init())
}
Why is the second assignment failing?
Adding the code modified to demonstrate what I was trying to do. I thought interfaces where more similar to C++ classes. My fault. Still learning
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m *MyProcessor) Init() int {
m.a++
return m.a
}
func main() {
t := &(MyProcessor{2})
m := MyProcessor{4}
var p LogProcessor = &m
fmt.Println(t.Init(), p.Init())
fmt.Println(t.a, m.a)
}
答案1
得分: 4
表达式MyProcessor{2}
是一个复合字面量。可以取复合字面量的地址,它的类型将是*MyProcessor
。
所以在这里:
t := &(MyProcessor{2})
t
的类型将是*MyProcessor
。
你的错误行:
var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
右侧表达式的类型再次是*MyProcessor
。它是一个指向具体类型的指针。p
的类型是*LogProcessor
,它是指向另一个类型的指针。可赋值性规则在这里不适用,因此该值无法赋给变量p
。
请注意,有一个可赋值性规则:
> 如果满足以下条件之一,则值x
可赋给类型为T
的变量(“x
可赋给T
”):
>
> - ...
> - T
是一个接口类型,并且x
实现了T
。
在你的示例中,p
的类型不是接口类型,而是指向接口的指针类型。在Go中,你很少(如果有的话)需要这样做。
相反,如果你使用“只是”接口类型:
var p LogProcessor = &(MyProcessor{4}) // 这样可以工作!
这样可以工作,因为具体类型*MyProcessor
实现了接口类型LogProcessor
。你也不需要括号,可以直接使用&MyProcessor{4}
。
然后当然你不能解引用p
(因为它不是指针),所以你必须使用p.Init()
。
英文:
The expression MyProcessor{2}
is a composite literal. It is valid to take the address of a composite literal, and it will be of type *MyProcessor
.
So here:
t := &(MyProcessor{2})
Type of t
will be *MyProcessor
.
Your failing line:
var p *LogProcessor = &(MyProcessor{4}) //!!!fails!!!
The type of the expression on the right hand side is again *MyProcessor
. It's a pointer to a concrete type. The type of p
is *LogProcessor
, it's a pointer to another type. Assignability rules don't apply here, so the value is simply not assignable to the variable p
.
Note that there is an assignability rule:
> A value x
is assignable to a variable of type T
("x
is assignable to T
") if one of the following conditions applies:
>
> - ...
> - T
is an interface type and x
implements T
.
In your example p
's type is not an interface type, but a pointer to interface. You rarely (if ever) need this in go.
Instead if you use "just" the interface type:
var p LogProcessor = &(MyProcessor{4}) // This works!
This works because the concrete type *MyProcessor
implements the interface type LogProcessor
. You also don't need the parenthesis, you may simply use &MyProcessor{4}
.
Then of course you can't dereference p
(as it's not a pointer), so you have to use p.Init()
.
答案2
得分: 1
它失败是因为你正在使用一个指向接口的指针,如果你移除变量p的LogProcessor指针,它就能正常工作。
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m MyProcessor) Init() int {
return 2
}
func main() {
t := &(MyProcessor{2})
var p LogProcessor = MyProcessor{4} // 移除接口类型的指针后可以正常工作
fmt.Println((*t).Init(), (p).Init())
}
英文:
it is failing because you are using a pointer to an interface, if you remove the pointer to LogProcessor for var p it works
package main
import "fmt"
type LogProcessor interface {
Init() int
}
type MyProcessor struct {
a int
}
func (m MyProcessor) Init() int {
return 2
}
func main() {
t := &(MyProcessor{2})
var p LogProcessor = MyProcessor{4} // works without a pointer to the interface type
fmt.Println((*t).Init(), (p).Init())
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论