在Go语言中访问嵌入方法的方式

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

Accessing embedded methods in GoLang

问题

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

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

package Test

import (
	"fmt"
	"reflect"
)

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

//通用函数
func TestFunction(Value interface{}) {

	// 值是否包含BaseObject?reflect.TypeOf(Value).Contains...Implements??
	// 转换为BaseObject?BO := Value.(BaseObject)
	// 如果是,调用BO.ToString()
	// fmt.println(BO.ToString())
}

//基础对象
type BaseObject struct {
}

func (this *HCObject) ToString() string {
	return "[BaseObject]"
}

//测试对象
type TestObject struct {
	BaseObject
}

func (this *TestObject) ToString() string {
	return "[TestObject]"
}
英文:

I'm trying to create some generic functions in go that handle lots of different object types, some of the types embed a handy sub type I've created call BaseObject.

I can't seem to figure out how to test if 'Value interface{}' contains a BaseObject, or how to then call one of it's methods e.g. ToString()... which should return [TestObject] not [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]"
}

答案1

得分: 3

首先,有几点需要注意:

  • 在play.golang.org上提供可运行的代码示例是一个很好的做法。
  • 始终使用fmt对代码进行格式化。
  • ToString 应该是 String。参考 fmt.Stringer 接口。
  • 正如其他人指出的,试图在Go中编写Java或C++代码会导致很多困难。

说完这些,这里 是一个可运行的代码示例,它可以实现你想要的功能,但有一些限制。

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

这段代码使用了 reflect 包(只有在真正需要时才应该使用)。我建议你尝试运行这个示例,并深入了解 reflect,看看是否值得继续使用Go进行开发。

英文:

First of all, a couple of points:

  • It is a good practice to give links to working code examples at play.golang.org.
  • Always fmt your code.
  • ToString should be String. See fmt.Stringer interface.
  • As others have pointed out, trying to write Java of C++ in Go will end with a log of pain below the back.

With that said, this is a runnable example of the code that does what you want with many buts.

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

This code uses the reflect package (which is something you should do only when you really need it). I suggest you play with that example and dig into reflect to see, whether it's worth it to continue the way you go with Go.

答案2

得分: 2

你不会“嵌入”到interface{}中。接口本身具有方法集,并包含某个值及其类型信息。

你可以使用类型断言从接口中提取值。

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

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

如果你想检查多个类型,可以使用类型开关。在你的情况下,TestObjectBaseObject是完全不同的类型;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()
}

在这种情况下,SubBase,因为满足Sub接口的任何内容也满足Base接口。

英文:

You don't "embed" into an interface{}. Interfaces themselves have a method set, and contain some value and it's type information.

You extract a value from an interface using a Type Assertion.

Your test function could contain something like:

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

If you want to check for more than one type, you use a type switch. In your case, TestObject and BaseObject are completely different types; TestObject is not a BaseObject.

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

If you need to distinguish between the two types, with the embedding type having a superset of the embedded type's methods, define interfaces that match the methods you need.

type Base interface {
	MethodA()
}

type Sub interface {
	MethodA()
	MethodB()
}

In this case Sub is a Base, in that anything that fulfills the Sub interface, also fulfills the Base interface.

huangapple
  • 本文由 发表于 2014年9月2日 22:23:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/25625757.html
匿名

发表评论

匿名网友

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

确定