我有一个带有点MVC架构的gin-gonic web应用程序。我创建了几个模型,所有模型都嵌入了一个常见的结构:
type User struct {
ID int
Name string
}
type Admin struct {
User
Level int
}
... {
User
}
现在我想以json格式将它们存储在数据库中。我想要实现的目标是只编写一个将编组任何模型的函数/方法,并将其保存到DB中。此方法必须封送当前模型的所有字段,而不仅仅是来自User struct,例如,用户必须被整理到{id: 1, name: "zhora"}
,而管理员则会进入{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
复制/粘贴到每个模型文件,只更改方法接收器。这可以避免吗?
答案 0 :(得分:3)
你可以像这样使用一个func Save(d interface{})
:
package main
import (
"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 main
import (
"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提供自动支持。有 自己提供吸气剂和制定者并没有错,而且确实如此 通常适合这样做,但它既不是惯用的,也不是必需的 将Get放入getter的名字。如果您有一个名为owner的字段 (小写,未导出),getter方法应该称为Owner (大写,导出),而不是GetOwner。使用大写名称 export提供了用于区分字段和方法的钩子。一个 如果需要,setter函数可能会被称为SetOwner。两个名字 在实践中读得很好:
owner := obj.Owner() if owner != user { obj.SetOwner(user) }