英文:
Why does Go allow me to call methods that are not implemented?
问题
Go似乎没有强制要求结构体遵循接口。为什么以下代码能够编译通过?
package main
type LocalInterface interface {
SomeMethod(string) error
SomeOtherMethod(string) error
}
type LocalStruct struct {
LocalInterface
myOwnField string
}
func main() {
var localInterface LocalInterface = &LocalStruct{myOwnField:"test"}
localInterface.SomeMethod("calling some method")
}
看起来这段代码不应该编译通过,因为SomeMethod
没有被实现。但是使用go build
命令并没有报错。
运行代码会导致运行时错误:
> go run main.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x4013b0]
goroutine 1 [running]:
panic(0x460760, 0xc08200a090)
C:/Go/src/runtime/panic.go:464 +0x3f4
main.(*LocalStruct).SomeMethod(0xc0820064e0, 0x47bf30, 0x13, 0x0, 0x0)
<autogenerated>:3 +0x70
main.main()
C:/Users/kdeenanauth/Documents/git/go/src/gitlab.com/kdeenanauth/structTest/main.go:16 +0x98
exit status 2
英文:
Go doesn't seem to enforce the struct adhering to the interface. Why does the following code compile?
<!-- language: go -->
package main
type LocalInterface interface {
SomeMethod(string) error
SomeOtherMethod(string) error
}
type LocalStruct struct {
LocalInterface
myOwnField string
}
func main() {
var localInterface LocalInterface = &LocalStruct{myOwnField:"test"}
localInterface.SomeMethod("calling some method")
}
It seems like this should not compile since SomeMethod
is not implemented.go build
results in no issues.
Running it results in the runtime error:
> go run main.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x4013b0]
goroutine 1 [running]:
panic(0x460760, 0xc08200a090)
C:/Go/src/runtime/panic.go:464 +0x3f4
main.(*LocalStruct).SomeMethod(0xc0820064e0, 0x47bf30, 0x13, 0x0, 0x0)
<autogenerated>:3 +0x70
main.main()
C:/Users/kdeenanauth/Documents/git/go/src/gitlab.com/kdeenanauth/structTest/main.go:16 +0x98
exit status 2
答案1
得分: 7
当一个类型被嵌入(例如,在你的例子中,LocalInterface
被嵌入在 LocalStruct
中),Go 会创建一个嵌入类型的字段,并将其方法提升到包含它的类型中。
所以以下声明:
type LocalStruct struct {
LocalInterface
myOwnField string
}
等同于
type LocalStruct struct {
LocalInterface LocalInterface
myOwnField string
}
func (ls *LocalStruct) SomeMethod(s string) error {
return ls.LocalInterface.SomeMethod(s)
}
你的程序因为 LocalInterface
字段是 nil
而导致空指针解引用的恐慌。
以下程序“修复”了这个恐慌(http://play.golang.org/p/Oc3Mfn6LaL):
package main
type LocalInterface interface {
SomeMethod(string) error
}
type LocalStruct struct {
LocalInterface
myOwnField string
}
type A int
func (a A) SomeMethod(s string) error {
println(s)
return nil
}
func main() {
var localInterface LocalInterface = &LocalStruct{
LocalInterface: A(10),
myOwnField: "test",
}
localInterface.SomeMethod("calling some method")
}
英文:
When a type is embedded (in your example LocalInterface
is embedded inside LocalStruct
), Go creates a field of the embedded type and promotes its methods to the enclosing type.
So the following declaration
type LocalStruct struct {
LocalInterface
myOwnField string
}
is equivalent to
type LocalStruct struct {
LocalInterface LocalInterface
myOwnField string
}
func (ls *LocalStruct) SomeMethod(s string) error {
return ls.LocalInterface.SomeMethod(s)
}
Your program panics with nil pointer dereference because LocalInterface
field is nil
.
The following program "fixes" the panic (http://play.golang.org/p/Oc3Mfn6LaL):
package main
type LocalInterface interface {
SomeMethod(string) error
}
type LocalStruct struct {
LocalInterface
myOwnField string
}
type A int
func (a A) SomeMethod(s string) error {
println(s)
return nil
}
func main() {
var localInterface LocalInterface = &LocalStruct{
LocalInterface: A(10),
myOwnField: "test",
}
localInterface.SomeMethod("calling some method")
}
答案2
得分: 1
进一步调查后,我发现避免嵌入可以得到适当的错误处理。在我的情况下,这将是首选方法:
package main
type LocalInterface interface {
SomeMethod(string) error
SomeOtherMethod(string) error
}
type LocalStruct struct {
myOwnField string
}
func main() {
var localInterface LocalInterface = &LocalStruct{myOwnField:"test"}
localInterface.SomeMethod("calling some method")
}
结果为:
.\main.go:13: 无法将 LocalStruct 字面量(类型 *LocalStruct)分配给 LocalInterface 类型:
*LocalStruct 未实现 LocalInterface(缺少 SomeMethod 方法)
英文:
Upon further investigation I found that avoiding embedding gets the proper error handling treatment. That would be preferred in my case:
<!-- language: go -->
package main
type LocalInterface interface {
SomeMethod(string) error
SomeOtherMethod(string) error
}
type LocalStruct struct {
myOwnField string
}
func main() {
var localInterface LocalInterface = &LocalStruct{myOwnField:"test"}
localInterface.SomeMethod("calling some method")
}
Results in:
>.\main.go:13: cannot use LocalStruct literal (type *LocalStruct) as type LocalInterface in assignment:
*LocalStruct does not implement LocalInterface (missing SomeMethod method)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论