我正面临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主题中看到了一个“解决方案”,但是我认为这不是一个好的解决方案。
答案 0 :(得分:3)
GetStructName
是Parent
类型而不是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
//
//---