【问题标题】:Accessing embedded methods in GoLang访问 GoLang 中的嵌入式方法
【发布时间】:2014-09-02 14:23:13
【问题描述】:

我正在尝试在 go 中创建一些通用函数来处理许多不同的对象类型,其中一些类型嵌入了我创建的一个方便的子类型调用 BaseObject。

我似乎无法弄清楚如何测试“Value interface{}”是否包含 BaseObject,或者如何调用其中一种方法,例如ToString()... 应该返回 [TestObject] 而不是 [BaseObject]

package Test

import(
    "fmt"
    "reflect"
)

func main() {
    Value:=TestObject{}
    TestFunction(Value)
}

//Generic function
func TestFunction(Value interface{}){

    // Does value contain BaseObject? reflect.TypeOf(Value).Containes...Implements??
    //Convert to BaseObject? BO:=Value.(BaseObject)
    // If it does, call BO.ToString()
    //fmt.println(BO.ToString())
}

//Base Object
type BaseObject struct {
}
func (this *HCObject) ToString() string {
    return "[BaseObject]"
}

//Test Object
type TestObject struct{
    BaseObject
}
func (this *TestObject) ToString() string {
    return "[TestObject]"
}

【问题讨论】:

  • 有关interface{}的更多信息,另请参阅stackoverflow.com/a/23148998/6309
  • 如果您尝试在 Go 中执行“经典”OOP,您会感到失望。你确定找不到类似 Go 的解决方案吗?
  • 您最好不要尝试在 Go 中编写类风格的面向对象代码。 Go 没有类、子类、继承等等。
  • 这些是不是子类,因为没有继承。请阅读embeddingmethod sets。嵌入基本上是自动委托。
  • 类型嵌入在结构中,而不是在接口中。你看,这一切都变得多毛和丑陋。基于类的继承和结构嵌入之间确实存在巨大的阻抗不匹配。结构嵌入是一些很好的语法糖,可以减少输入几个字符。就是这样。

标签: go embedding


【解决方案1】:

首先,有几点:

  • 最好在 play.golang.org 上提供工作代码示例的链接。
  • 始终 fmt 您的代码。
  • ToString 应该是 String。见fmt.Stringer接口。
  • 正如其他人所指出的那样,尝试在 Go 中编写 C++ 的 Java 会以背部下方的痛苦记录结束。

话虽如此,this 是一个可运行的代码示例,可以满足您的各种需求。

func TestFunction(v interface{}) {
    fmt.Println(reflect.ValueOf(v).FieldByName("BaseObject").MethodByName("String").Call(nil)[0].String())
}

此代码使用reflect 包(只有在您真正需要它时才应该这样做)。我建议您使用该示例并深入了解reflect 看看是否值得继续使用 Go 的方式。

【讨论】:

  • 这看起来像是解决方案。我仍在尝试让它在我自己的代码中工作,但你是 play.golang.org 上的演示作品。谢谢。
  • @GordonTruslove:在这种情况下不需要使用反射(你应该尽可能避免它)——你可以使用接口EXAMPLE 完全做到这一点。请注意,您必须确保传递一个与方法集匹配的指针。
  • 那个例子是最好的解决方案。我将尝试实现这一点。实现所有额外的接口方法只是意味着一些额外的工作。谢谢。
【解决方案2】:

您不会“嵌入”到interface{}。接口本身有一个方法集,并包含一些值和它的类型信息。

您使用Type Assertion 从接口中提取值。

您的测试函数可能包含以下内容:

bo, ok := value.(BaseObject)
if ok {
  fmt.Println(bo)
}

如果要检查多个类型,请使用类型开关。在您的情况下, TestObject 和 BaseObject 是完全不同的类型; TestObject 不是 BaseObject。

switch bo := value.(type) {
case TestObject:
    fmt.Println("TestObject", bo)
case BaseObject:
    fmt.Println("BaseObject", bo)
}

如果您需要区分这两种类型,并且嵌入类型具有嵌入类型方法的超集,请定义与您需要的方法匹配的接口。

type Base interface {
    MethodA()
}

type Sub interface {
    MethodA()
    MethodB()
}

在这种情况下,Sub 是一个Base,因为任何满足Sub 接口的东西,也满足Base 接口。

【讨论】:

  • 我之前尝试过这两种方法,但都没有奏效。只有 value.(TestObject) 和 case TestObject: 有效。
  • 尝试创建可运行的示例。类型断言的错误说明了您的问题panic: interface conversion: interface is main.TestObject, not main.BaseObject。同样,Go 中没有继承。没有 type->embedded-type is-a 关系。嵌入只是一种方便的委托形式,您使用接口来实现多态性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多