在超类中找不到子类的接口方法。

huangapple go评论78阅读模式
英文:

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接口。似乎在调用cloneAndGetNamemain中的具体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.BaseItf1nil。你不能从类型为*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{&amp;SubClass{}}
fmt.Printf(&quot;-&gt; %s\n&quot;, sc.clone().getName())
fmt.Printf(&quot;-&gt; %s\n&quot;, 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 &quot;&lt;nil&gt;&quot;
}

func (bs *BaseStruct) clone() *BaseStruct {
  if bs.sub != nil {
    return bs.sub.clone()
  }
  // default behavior
  return bs
}

type SubClass struct {
  // Doesn&#39;t need to embed BaseStruct
  // ...
}

func (sc *SubClass) getName() string {
  return &quot;A&quot;
}

func (sc *SubClass) clone() *BaseStruct {
  return &amp;BaseStruct{&amp;SubClass{}}
}

https://play.golang.org/p/CWdScZMXZ_

答案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 (
	&quot;fmt&quot;
)

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 &quot;&quot;
}

func (bs *BaseStruct) clone() *BaseStruct {
	return nil
}

type SubClass struct {
	BaseStruct
}

func (sc *SubClass) getName() string {
	return &quot;A&quot;
}

func (sc *SubClass) clone() *SubClass {
	return &amp;SubClass{}
}

func main() {
	sc := &amp;SubClass{}
	fmt.Printf(&quot;-&gt; %s\n&quot;, sc.clone().getName())
	fmt.Printf(&quot;-&gt; %s\n&quot;, 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  &lt;fieldName&gt; &lt;Type&gt;
}

func (bs *BaseStruct) clone() *BaseStruct {
	return &amp;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 &quot;a BaseStruct has no name&quot;
}

func (bs *BaseStruct) cloneAndGetName() string {
	sc := bs.clone()
	return sc.getName()
}

type SubClass struct {
	BaseStruct
}

func (sc *SubClass) methodA() string {
  return &quot;A&quot;
}

func (sc *SubClass) methodB() *SubClass {
  return &amp;SubClass{}
}

func main() {
	sc := &amp;SubClass{}
	
	fmt.Printf(&quot;type: %T and value: %v \n\n&quot;, sc.BaseItf1, sc.BaseItf1)
	
	fmt.Printf(&quot;-&gt; %q\n&quot;, sc.clone().getName())
	fmt.Printf(&quot;-&gt; %q\n&quot;, sc.cloneAndGetName())
}

https://play.golang.org/p/tHScVktrDZ

huangapple
  • 本文由 发表于 2016年11月21日 11:10:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/40712193.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定