获取外部/父结构名称

时间:2019-01-20 15:06:16

标签: go

我正面临Golang初学者的问题,而且我不知道如何正确解决它。你能帮我吗?

信息:即使这与Go的概念(不是试图成为一种OOP语言)背道而驰,我还是想讨论一些解决方案。

我想知道接收者/子对象中的外部/父结构名称。请查看以下代码(游乐场:https://play.golang.org/p/h6dARJQwidS

package main

import (
    "fmt"
    "reflect"
)

type Parent struct {
    Id uint32
}

func (p *Parent) GetStructName() string {
    return reflect.TypeOf(p).Elem().Name()
}


type Child struct {
    Parent
}


func main() {
    myChild := Child{}
    fmt.Println(myChild.GetStructName()) // Gives "Parent" instead of "Child". How to get "Child"?
}

尽管结构是“ Child”,但它显示“ Parent”。谁能告诉我如何获取正确的结构名称?我在另一个“正确”(Go - get parent struct)工作的stackoverflow主题中看到了一个“解决方案”,但是我认为这不是一个好的解决方案。

3 个答案:

答案 0 :(得分:3)

GetStructNameParent类型而不是Child类型的方法,Golang也没有继承,而是有结构嵌入(也有接口嵌入),这是一种像继承一样,但有一个关键的区别:

  

当我们嵌入一个类型时,该类型的方法成为外部类型的方法,但是当调用它们时,该方法的接收者是内部类型,而不是外部类型。

这基本上意味着,当您调用GetStructName时,该方法的接收者是Parent(内部或嵌入式类型),而不是Child

这与典型的类继承有根本的不同,它解释了您所看到的行为。

有据可查的here

答案 1 :(得分:0)

虽然丹尼尔(Daniel)的回答回答了问题的“原因”,但是您仍然可以通过“有点儿丑陋”的方式来“整理”出您可能正在寻找的行为:

package main

import (
    "fmt"
    "reflect"
)

type NamedReturningType interface {
    GetStructName() string
}

type Parent struct {
    Id uint32
}

func (p *Parent) GetStructName() string {
    return reflect.TypeOf(p).Elem().Name()
}


type Child struct {
    Parent
}

func (c *Child) GetStructName() string {
    return reflect.TypeOf(c).Elem().Name()
}

func main() {

    myChild := Child{}
    fmt.Println(myChild.GetStructName())

    myParent := Parent{}
    fmt.Println(myParent.GetStructName())
}

(游乐场:https://play.golang.org/p/qEtoEulFSPy

编辑:添加了这些类型可以实现的接口,以使代码更通用。

答案 2 :(得分:0)

出于完整性考虑,我想分享我的解决方案(游乐场:https://play.golang.org/p/tUhlz_o8Z7V)。

如我最初的问题中所述,该想法来自Go - get parent struct

这也与我在这里看到的Go2请求有关:https://github.com/golang/go/issues/28254

package main

import (
    "fmt"
    "log"
    "reflect"
)

// we need an interface so methods are being embedded automatically
type IParent interface {
    Init(IParent)   IParent
}

// internal private fields, non-visible from the outside
type Parent struct {
    _IsInitialized  bool
    _Self           IParent
}

// init the struct, set "_Self" to it's caller
func (p *Parent) Init(o IParent) IParent {
    p._Self = o
    p._IsInitialized = true
    return o
}

// This method uses "_Self" to determine what it actually is
func (p *Parent) GetStructName() string {
    if !p._IsInitialized {
        log.Fatal("Struct not initialized. You may call 'myVar.Init(&myVar)' to initialize it.")
    }
    return reflect.TypeOf(p._Self).Elem().Name()
}

// Below childs have "Init()" from Parent, so they implement IParent automatically
// No need to duplicate any methods here anymore
type Child1 struct {
    Parent
}

type Child2 struct {
    Parent
}

type Child3 struct {
    Parent
}

type Child4 struct {
    Parent
}

func main() {
    myChild1 := Child1{}
    myChild1.Init(&myChild1) // Init object (set _Self on struct)
    fmt.Println(myChild1.GetStructName()) // Gives "Child1"

    myChild2 := Child2{}
    myChild2.Init(&myChild2) // Init object (set _Self on struct)
    fmt.Println(myChild2.GetStructName()) // Gives "Child2"

    myChild3 := Child3{}
    myChild3.Init(&myChild3) // Init object (set _Self on struct)
    fmt.Println(myChild3.GetStructName()) // Gives "Child3"

    myChild4 := Child4{}
    fmt.Println(myChild4.GetStructName()) // Fatal error
}

// Footnotes:
//---
//
//  This attempt tries to solve a go 'inheritance' problem although go is *NOT* meant to be an OOP language. It was a funny experiment still :-)
//  License: open domain, no attribution
//  https://www.xsigndll.com
//
//---