英文:
Interface method can't be found on subclass from super class
问题
给定这段代码...
type BaseItf1 interface {
getName() string
clone() *BaseStruct
}
type BaseStruct struct {
BaseItf1
}
func (bs *BaseStruct) cloneAndGetName() string {
sc := bs.clone()
return sc.getName()
}
type SubClass struct {
BaseStruct
}
func (sc *SubClass) getName() string {
return "A"
}
func (sc *SubClass) clone() *SubClass {
return &SubClass{}
}
func main() {
sc := &SubClass{}
fmt.Printf("-> %s\n", sc.clone().getName())
fmt.Printf("-> %s\n", sc.cloneAndGetName())
}
我无法完全弄清楚为什么会出现以下错误:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0x2004a]
在main
中对clone
的调用完全正常。
然而,在cloneAndGetName
中,无法调用clone
方法。bs
的类型是指向BaseStruct
的指针,它具有具有clone
方法的BaseItf
接口。似乎在调用cloneAndGetName
的main
中的具体sc
实例知道如何定位clone
方法。
我漏掉了什么?有没有更好的方法来解决这个问题?在我的实际代码中,我需要一种从一些共享代码创建对象的方法。
英文:
Given this code...
type BaseItf1 interface {
getName() string
clone() *BaseStruct
}
type BaseStruct struct {
BaseItf1
}
func (bs *BaseStruct) cloneAndGetName() string {
sc := bs.clone()
return sc.getName()
}
type SubClass struct {
BaseStruct
}
func (sc *SubClass) getName() string {
return "A"
}
func (sc *SubClass) clone() *SubClass {
return &SubClass{}
}
func main() {
sc := &SubClass{}
fmt.Printf("-> %s\n", sc.clone().getName())
fmt.Printf("-> %s\n", sc.cloneAndGetName())
}
I can't quite figure out why I'm getting this error:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0x2004a]
The call to clone
in main
works perfectly, naturally.
In cloneAndGetName
, however, the clone
method can't be invoked. bs
is typed to a pointer to BaseStruct
, which has the BaseItf
interface with the clone
method. It would seem like the concrete sc
instance in main
that invoked cloneAndGetName
knows how to locate the clone
method.
What am I missing? Is there a better way to go about this? In my real code, I need a way to create a new instance of an object from some shared code.
答案1
得分: 2
bs.clone()
失败是因为它试图调用bs.BaseItf1.clone()
,而bs.BaseItf1
是nil
。你不能从类型为*BaseStruct
的变量中调用为*SubClass
定义的clone()
方法。在Go语言中,嵌入类型与其他语言中的子类化不同。
英文:
bs.clone()
fails because it's trying to call bs.BaseItf1.clone()
and bs.BaseItf1
is nil
. You can't call the clone()
defined for *SubClass
from a variable of type *BaseStruct
. Embedding types in Go is not the same as subclassing in other languages.
答案2
得分: 1
你正在混淆嵌入和接口实现。在当前状态下,你有一个结构体 SubClass
,它嵌入了结构体 BaseStruct
,而后者又嵌入了接口 BaseItf1
。然而,你有一个问题:SubClass
没有覆盖 cloneAndGetName()
方法。因此,该方法在嵌入的 BaseStruct
结构体上调用。嵌入方法的调用是使用 嵌入结构体 作为接收者,而不是嵌入结构体本身。因此,BaseStruct
只能访问自己的方法,而不能访问包裹它的 SubClass
结构体的方法。由于这些方法本身是嵌入的 BaseItf1
接口的结果,BaseStruct
在该嵌入接口上调用这些方法时会出现 nil
。当然,这会触发一个段错误。
在这种情况下,你似乎想要在某个基本结构上定义一个标准方法,然后能够用子类覆盖该行为。在这种情况下,将 SubClass
的实例放入 BaseClass
中的接口字段中:
sc := BaseStruct{&SubClass{}}
fmt.Printf("-> %s\n", sc.clone().getName())
fmt.Printf("-> %s\n", sc.cloneAndGetName())
在这个示例中,sc.cloneAndGetName()
将在 BaseStruct
上调用,但 clone()
和 getName()
的调用将在子结构上进行。
甚至可以在接口为 nil
时定义默认行为:
type BaseItf1 interface {
getName() string
clone() *BaseStruct
}
type BaseStruct struct {
sub BaseItf1
}
func (bs *BaseStruct) cloneAndGetName() string {
sc := bs.clone()
return sc.getName()
}
func (bs *BaseStruct) getName() string {
if bs.sub != nil {
return bs.sub.getName()
}
// 默认行为
return "<nil>"
}
func (bs *BaseStruct) clone() *BaseStruct {
if bs.sub != nil {
return bs.sub.clone()
}
// 默认行为
return bs
}
type SubClass struct {
// 不需要嵌入 BaseStruct
// ...
}
func (sc *SubClass) getName() string {
return "A"
}
func (sc *SubClass) clone() *BaseStruct {
return &BaseStruct{&SubClass{}}
}
链接:https://play.golang.org/p/CWdScZMXZ_
英文:
You're confusing embedding with interface fulfillment. In its current state, you have a struct SubClass
which embeds the struct BaseStruct
, which then embeds an interface BaseItf1
. However, you have a problem: SubClass
does not override the cloneAndGetName()
method. As such, this method is called on the embedded BaseStruct
struct. Embedded method calls are invoked using the embedded struct as the receiver, not the embedding struct. The BaseStruct
struct thus only has access to its own methods, not those of the SubClass
struct wrapping it. Since those methods themselves are the result of the embedded BaseItf1
interface, BaseStruct
calls those methods on that embedded interface, which is nil
. This, of course, triggers a segfault.
In this case, it appears that you want to have a standard method defined on some base structure, but then be able to override that behavior with a subclass. In this case, place an instance of SubClass
into the interface field within the BaseClass
:
sc := BaseStruct{&SubClass{}}
fmt.Printf("-> %s\n", sc.clone().getName())
fmt.Printf("-> %s\n", sc.cloneAndGetName())
In this instance, sc.closeAndGetName()
will be called on the BaseStruct
, but the clone()
and getName()
calls will occur on the substruct.
You can even define default behavior if the interface is nil:
type BaseItf1 interface {
getName() string
clone() *BaseStruct
}
type BaseStruct struct {
sub BaseItf1
}
func (bs *BaseStruct) cloneAndGetName() string {
sc := bs.clone()
return sc.getName()
}
func (bs *BaseStruct) getName() string {
if bs.sub != nil {
return bs.sub.getName()
}
// default behavior
return "<nil>"
}
func (bs *BaseStruct) clone() *BaseStruct {
if bs.sub != nil {
return bs.sub.clone()
}
// default behavior
return bs
}
type SubClass struct {
// Doesn't need to embed BaseStruct
// ...
}
func (sc *SubClass) getName() string {
return "A"
}
func (sc *SubClass) clone() *BaseStruct {
return &BaseStruct{&SubClass{}}
}
答案3
得分: 0
你应该先在接口中实现这个函数。
package main
import (
"fmt"
)
type BaseItf1 interface {
getName() string
clone() *BaseStruct
}
type BaseStruct struct {
BaseItf1
}
func (bs *BaseStruct) cloneAndGetName() string {
sc := bs.clone()
return sc.getName()
}
func (bs *BaseStruct) getName() string {
return ""
}
func (bs *BaseStruct) clone() *BaseStruct {
return nil
}
type SubClass struct {
BaseStruct
}
func (sc *SubClass) getName() string {
return "A"
}
func (sc *SubClass) clone() *SubClass {
return &SubClass{}
}
func main() {
sc := &SubClass{}
fmt.Printf("-> %s\n", sc.clone().getName())
fmt.Printf("-> %s\n", sc.cloneAndGetName())
}
英文:
you should implement the function in the interface first.
package main
import (
"fmt"
)
type BaseItf1 interface {
getName() string
clone() *BaseStruct
}
type BaseStruct struct {
BaseItf1
}
func (bs *BaseStruct) cloneAndGetName() string {
sc := bs.clone()
return sc.getName()
}
func (bs *BaseStruct) getName() string {
return ""
}
func (bs *BaseStruct) clone() *BaseStruct {
return nil
}
type SubClass struct {
BaseStruct
}
func (sc *SubClass) getName() string {
return "A"
}
func (sc *SubClass) clone() *SubClass {
return &SubClass{}
}
func main() {
sc := &SubClass{}
fmt.Printf("-> %s\n", sc.clone().getName())
fmt.Printf("-> %s\n", sc.cloneAndGetName())
}
答案4
得分: 0
当你有一个结构体并且想要满足一个接口时,你必须实现该接口的所有方法。当你有一个包含其他接口的接口时,情况就不同了。对于结构体来说,只需要有一个字段即可。如果你在代码中检查 sc.BaseItf1
,你会发现它的类型是 <nil>
,值也是 <nil>
,所以调用 .clone()
和 .cloneAndGetName()
方法会失败。在这里实现了这些方法:
type BaseItf1 interface {
getName() string
clone() *BaseStruct
}
type BaseStruct struct {
BaseItf1 // BaseItf1 的快捷方式 BaseItf1 <fieldName> <Type>
}
func (bs *BaseStruct) clone() *BaseStruct {
return &BaseStruct{}
}
func (bs *BaseStruct) getName() string {
//
// 或许 BaseStruct 应该有一个 Name 字段,不确定你是否想要这样
// 如果是这样的话,我们可以这样做:
//
// return bs.Name
return "一个 BaseStruct 没有名字"
}
func (bs *BaseStruct) cloneAndGetName() string {
sc := bs.clone()
return sc.getName()
}
type SubClass struct {
BaseStruct
}
func (sc *SubClass) methodA() string {
return "A"
}
func (sc *SubClass) methodB() *SubClass {
return &SubClass{}
}
func main() {
sc := &SubClass{}
fmt.Printf("type: %T and value: %v \n\n", sc.BaseItf1, sc.BaseItf1)
fmt.Printf("-> %q\n", sc.clone().getName())
fmt.Printf("-> %q\n", sc.cloneAndGetName())
}
链接:https://play.golang.org/p/tHScVktrDZ
英文:
When you have a struct and you want to satisfy an interface you have to implement all the methods of that interface, it's different when you have an interface with other interface inside, for structs it's just having a field, if you check in the code sc.BaseItf1
has a type <nil> and value <nil>, so the call to .clone()
and .cloneAndGetName()
are failing. Implemented the methods here:
type BaseItf1 interface {
getName() string
clone() *BaseStruct
}
type BaseStruct struct {
BaseItf1 // shortcut to BaseItf1 BaseItf1 <fieldName> <Type>
}
func (bs *BaseStruct) clone() *BaseStruct {
return &BaseStruct{}
}
func (bs *BaseStruct) getName() string {
//
// maybe BaseStruct should have a field Name, not sure if you want to
// in that case we can do:
//
// return bs.Name
return "a BaseStruct has no name"
}
func (bs *BaseStruct) cloneAndGetName() string {
sc := bs.clone()
return sc.getName()
}
type SubClass struct {
BaseStruct
}
func (sc *SubClass) methodA() string {
return "A"
}
func (sc *SubClass) methodB() *SubClass {
return &SubClass{}
}
func main() {
sc := &SubClass{}
fmt.Printf("type: %T and value: %v \n\n", sc.BaseItf1, sc.BaseItf1)
fmt.Printf("-> %q\n", sc.clone().getName())
fmt.Printf("-> %q\n", sc.cloneAndGetName())
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论