一种处理嵌入一个通用结构的所有结构类型的方法(json 编组)

我有一个带有某种 MVC 架构的 gin-gonic 网络应用程序。我创建了几个模型,它们都嵌入了一个通用结构:


type User struct {

   ID int

   Name string

}


type Admin struct {

   User

   Level int

}


... {

   User

}

现在我想将它们以 json 格式存储在数据库中。我想要完成的目标是只编写一个函数/方法来编组任何模型并将其保存到数据库中。此方法必须编组当前模型的所有字段,不仅来自 User 结构,例如 User 必须编组到{id: 1, name: "zhora"},而 Admin 将进入{id: 1, name: "gena", level: 2}。


像这个:


func (i *User) Save() {

  data, err := json.Marshal(i)

  check(err)

  if i.ID == 0 {

    _, err = app.DB.Exec(`INSERT INTO users(data) VALUES ($1) `, string(data))

  } else {

    _, err = app.DB.Exec(`UPDATE users SET data = $1 WHERE id=$2`, string(data), i.ID)

  }

  check(err)

}

现在我必须将它复制/粘贴func到每个模型文件中,只更改方法接收器。这可以避免吗?


湖上湖
浏览 116回答 1
1回答

慕娘9325324

您可以使用func Save(d interface{})这样的一种:package mainimport (    "encoding/json"    "fmt")type User struct {    ID   int    Name string}type Admin struct {    User    Level int}func main() {    Save(User{})    Save(Admin{})}func Save(d interface{}) {    body, err := json.Marshal(d)    if err != nil {        panic(err)    }    st := string(body)    fmt.Println(st)}输出:{"ID":0,"Name":""}{"ID":0,"Name":"","Level":0}对于您的情况,请对所有类型使用此功能:func Save(i interface{}, id int) {    data, err := json.Marshal(i)    check(err)    if id == 0 {        _, err = app.DB.Exec(`INSERT INTO users(data) VALUES ($1) `, string(data))    } else {        _, err = app.DB.Exec(`UPDATE users SET data = $1 WHERE id=$2`, string(data), id)    }    check(err)}并这样称呼它:u := User{}a := Admin{}Save(u, u.ID)Save(a, a.ID)是的,这甚至简化了Save对一个参数的调用:package mainimport (    "encoding/json"    "fmt")type Model interface {    ID() int    setID(int)}type User struct {    Id   int    Name string}func (t User) ID() int      { return t.Id }func (t User) setID(id int) { t.Id = id }type Admin struct {    User    Level int}func main() {    Save(User{})    Save(Admin{})}func Save(d Model) {    body, err := json.Marshal(d)    if err != nil {        panic(err)    }    st := string(body)    fmt.Println(st)    fmt.Println("ID is ", d.ID())}输出:{"Id":0,"Name":""}ID is  0{"Id":0,"Name":"","Level":0}ID is  0现在您可以将这一功能用于所有类型:func Save(i Model) {    data, err := json.Marshal(i)    check(err)    id := i.ID()    if id == 0 {        _, err = app.DB.Exec(`INSERT INTO users(data) VALUES ($1) `, string(data))    } else {        _, err = app.DB.Exec(`UPDATE users SET data = $1 WHERE id=$2`, string(data), id)    }    check(err)}并这样称呼它:u := User{}a := Admin{}Save(u)Save(a)有效围棋:吸气剂Go 不提供对 getter 和 setter 的自动支持。自己提供 getter 和 setter 并没有错,而且这样做通常是合适的,但是将 Get 放入 getter 的名称中既不习惯也没有必要。如果您有一个名为 owner(小写,未导出)的字段,则 getter 方法应称为 Owner(大写,已导出),而不是 GetOwner。使用大写名称进行导出提供了将字段与方法区分开来的钩子。如果需要,setter 函数可能会被称为 SetOwner。这两个名字在实践中都很好读:owner := obj.Owner()if owner != user {    obj.SetOwner(user)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go