How to add a method for different structs which have one common field in golang

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

How to add a method for different structs which have one common field in golang

问题

我正在使用beego/orm来开发我的应用程序。这里有两个模型:

type ModelA struct {
    Guid   string `orm:"pk"`
    FiledA string
}

type ModelB struct {
    Guid   string `orm:"pk"`
    FiledB string
}

我需要为每个结构体添加一个Save()方法。通常情况下,我可以创建一个Base结构体,并将其混入ModelAModelB,但是orm可能无法正常工作。

有没有更好的解决方案?

编辑1: 在这里提供Save()方法的代码,以使问题更清晰:

func (this *ModelA) Save() error {
    o := orm.NewOrm()
    guid := guidlib.Generate()
    this.Guid = guid
    _, err := o.Insert(this)
    return err
}

func (this *ModelB) Save() error {
    o := orm.NewOrm()
    guid := guidlib.Generate()
    this.Guid = guid
    _, err := o.Insert(this)
    return err
}
英文:

I'm using beego/orm for my app. Here I have 2 models

type ModelA struct {
    Guid string `orm:"pk"`
    FiledA string
}

type ModelB struct {
    Guid string `orm:"pk"`
    FiledB string
}

I need to add a Save() method for each struct. In general, I can create an Base struct and mixin it into ModelA and ModelB, but the orm would not work.

Is there any better solution?

edit1: Giving Save() code here to make question more clear

func (this *ModelA) Save() error {
    o := orm.NewOrm()
    guid := guidlib.Generate()
    this.Guid = guid
    _, err := o.Insert(this)
    return err
}

func (this *ModelB) Save() error {
    o := orm.NewOrm()
    guid := guidlib.Generate()
    this.Guid = guid
    _, err := o.Insert(this)
    return err
}

答案1

得分: 7

是的。定义一个接口。另外,虽然我很确定你在谈论嵌入,但是Go语言中并不存在"mixin"的概念。下面是一些伪代码来演示这些结构。

type Savable interface {
    Save()
}

// ModelA满足Savable接口
func (a ModelA) Save() {
    // 做一些操作
}

var i Savable
i = SomeMethodThatRetunsMyModel()
i.Save()
SomeOthermMethodThatAcceptsASavableAndCallesSave(i)

嵌入的方法:

type ModelA struct {
    ModelC
    FiledA string
}

type ModelB struct {
    ModelC
    FiledB string
}

type ModelC struct {
    Guid string `orm:"pk"`
}

func (this ModelC) Save() error {
    o := orm.NewOrm()
    guid := guidlib.Generate()
    this.Guid = guid
    _, err := o.Insert(this)
    return err
}

然而,需要注意的是o.Insert(this)不会插入在ModelC中未定义的任何字段。正如我在下面的评论中提到的,使用继承结构的类型,其中模型A和B将重新实现Save并在前面调用基类方法的类型,在Go语言中并不适用。

嵌入类型的方法解析规则并不完全清晰,可能会令人困惑。你可以在嵌入的结构体中定义一个版本的Save方法,在嵌入者中重新定义它,并在该方法中调用它,但这样做并没有太多意义。如果你仍然需要静态引用嵌入类型,我建议避免使用嵌入。例如,如果我有一个ModelA嵌入了ModelC,并且在更广泛的范围内,我必须使用ModelA.ModelC.SomeMethodThatIhaveToReferencExplicitlyToEnsureItsCalled(),那么我可能没有很好地使用这个特性。

英文:

Yes. Define an interface. Also, hate to nitpick, while I'm pretty sure you're talking about embedding there isn't a 'mixin' concept that exists in Go. Here's some pseudo code that demonstrates the constructs.

type Savable interface {
       Save()
}

// satisfies Savable for ModelA
func (a ModelA) Save() {
      // do something
}

var i Savable
i = SomeMethodThatRetunsMyModel()
i.Save()
SomeOthermMethodThatAcceptsASavableAndCallesSave(i)

The embedding approach:

type ModelA struct {
    ModelC
    FiledA string
}

type ModelB struct {
    ModelC
    FiledB string
}

type ModelC struct {
    Guid string `orm:"pk"`
}

func (this ModelC) Save() error {
    o := orm.NewOrm()
    guid := guidlib.Generate()
    this.Guid = guid
    _, err := o.Insert(this)
    return err
}

However, note that o.Insert(this) is not going to insert any fields that aren't defined on ModelC. As I mentioned in my comment below the type of inheritance structure that might be used where models A and B would reimplement Save calling the base classes method upfront doesn't really work well in Go.

The rules for method resolution with embedded types aren't completely clear and can be confusing. You could define one version of Save in the embedded structs, redefine it in the embedor and even call it within that method however it doesn't really make much sense to do. I would make a point to avoid embedding if you're still going to have to statically reference the embedded type. For example if I have ModelA embedding ModelC and in the broader scope I'm having to do ModelA.ModelC.SomeMethodThatIhaveToReferencExplicitlyToEnsureItsCalled() then I'm probably making poor use of the feature.

答案2

得分: -2

不,你不能这样做,因为Golang不支持继承。但你可以尝试以下类似的方法:

func Save(obj interface{}) error {
    o := orm.NewOrm()
    guid := guidlib.Generate()
    r := reflect.ValueOf(obj)
    f := reflect.Indirect(r).FieldByName("Guid")
    f.SetString(guid)
    _, err := o.Insert(obj)
    return err
}

请注意,如果没有名为"Guid"的字段,这段代码会引发错误。

英文:

No, you can not do this because Golang does not support inheritance. But you can do something like this below:

func Save(obj interface{}) error {
    o := orm.NewOrm()
    guid := guidlib.Generate()
    r := reflect.ValueOf(obj)
    f := reflect.Indirect(r).FieldByName("Guid") 
    f.setString(guid)  
    _, err := o.Insert(obj)
    return err
}

Be careful, it will panic if there is no field "guid"

huangapple
  • 本文由 发表于 2015年11月11日 09:19:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/33642708.html
匿名

发表评论

匿名网友

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

确定