从父方法访问所有字段

时间:2016-10-24 09:47:58

标签: go struct dry embedding

我正在开发一个将数据存储在mongodb中的应用程序。有几个集合,当然所有集合都有一些共同的字段(如Id,创建日期等)和方法(例如Insert)。在我的视野中,我需要使用所需的字段和方法创建基本模型结构,然后将此结构嵌入到我的模型中。不幸的是,这不起作用,因为为基本模型定义的方法看不到子字段。

我不知道如何进一步解释。这是操场上的代码: https://play.golang.org/p/_x-B78g4TV

它使用json而不是mgo,但想法仍然相同。

我希望输出为:

  

保存到'my_model_collection'

     

{“_ id”:42,“foo”:“foo的一些值”,“bar”:“这里我们为bar设置一些值”}

  

保存到'my_model_collection'

     

{ “_编码”:42}

为每个我的模型编写插入方法似乎是反对DRY,那么在Go中实现这一点的正确/惯用方法是什么?

3 个答案:

答案 0 :(得分:2)

这是不可能的,有关详细信息,请参阅我的回答:Can embedded struct method have knowledge of parent/child?

你可以做两件事:

1。放弃方法并使其成为辅助/实用功能

我的想法是让Insert()BaseModel分离并使其成为一个简单的函数,然后将文档传递给您要保存的文档。

我个人更喜欢这个选项,因为它需要更少的麻烦和维护。它看起来像这样:

func Insert(doc interface{}) {
    j, _ := json.Marshal(doc)
    fmt.Println(string(j))
}

标签中也有“拼写错误”:

type MyModel struct {
    *BaseModel
    Foo string `json:"foo"`
    Bar string `json:"bar"`
}

使用它:

Insert(m)

输出(在Go Playground上尝试):

{"_id":42,"foo":"Some value for foo","bar":"Here we set some value for bar"}

2。将包装器的(指针)传递给BaseModel

在这种方法中,你必须传递一个指向embedder结构的指针,这样BaseModel.Insert()方法将有一个指向它的指针,并可以使用它来保存/编组。这基本上是手动维护嵌入我们并正在保存/编组的结构的“引用”。

这就是它的样子:

type BaseModel struct {
    Id             int `json:"_id"`
    collectionName string

    wrapper interface{}
}

然后在Insert()方法中保存wrapper

func (m *BaseModel) Insert() {
    fmt.Printf("Saving to '%v'\n", m.collectionName)
    j, _ := json.Marshal(m.wrapper)
    fmt.Println(string(j))
}

创作稍微复杂一些:

func NewMyModel() *MyModel {
    mm := &MyModel{
        Foo: "Some value for foo",
    }
    mm.BaseModel = NewBaseModel("my_model_collection", mm)
    return mm
}

但输出是你想要的:

Saving to 'my_model_collection'
{"_id":42,"foo":"Some value for foo","bar":"Here we set some value for bar"}

Go Playground上尝试。

答案 1 :(得分:1)

在Golang中,您无法覆盖父方法,因为这不是多态的工作方式。 Insert方法将适用于BaseModel成员,而不适用于MyModel

此外,您正试图以不正当的方式使用mgo。如果您想在集合中插入文档,那么您已经拥有Insert结构的Collection方法,该方法适用于interface{}类型(与json.Marshal相同)。

当然,您可以拥有一个BaseModel,其中包含您所有模型共享的字段。事实上,GORM使用类似的方法,并提供一个Model结构,以包含在每个子模型中。

答案 2 :(得分:-1)

众所周知的问题; o)名称以小写字母开头的成员变量(如collectionName)在其他包(如json)中不可见。因此将struct更改为:

type BaseModel struct {
    Id             int    `json:"_id"`
    CollectionName string `json:"collectionName"`
}

世界将是更好的居住地。