一种处理所有嵌入一个公共结构(json编组)的结构类型的方法 [英] One method to handle all the struct types that embed one common struct (json marshalling)

查看:172
本文介绍了一种处理所有嵌入一个公共结构(json编组)的结构类型的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个有些MVC架构的杜松子酒网络应用程序。我创建了几个模型,它们都嵌入了一个常见的结构体:


$ b

  type User struct { 
ID int
名称字符串
}

类型管理结构{
用户
级别int
}

... {
User
}

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



像这样:

  func(i * User)Save(){
data,err:= json.Marshal(i)
check(err)
if 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),i.ID)
}
check(err)
}

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

解决方案

您可以使用一个 func Save(d interface {}) code>像这样:

package main

import (
encoding / json
fmt


类型用户结构{
ID int
名称字符串
}

类型结构{
用户
级别int
}

func main(){
Save(User { })
保存(Admin {})
}

func保存(d接口{}){
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:=用户{} 
a:=管理员{}

保存(u,u.ID)
保存(a,a.ID)






是的,这甚至简化了对 Save的调用添加到一个参数中:

  package main 

import(
encoding / json
fmt


类型模型接口{
ID()int
setID (int)


类型用户结构{
Id int
名称字符串
}

func(t User) ID()int {return t.Id}
func(t User)setID(id int){t.Id = id}

类型管理结构{
User
Level int

$ b $ func main(){
保存(用户{})
保存(管理{})
}

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为0
{Id:0,Name:,Level:0}
ID为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))
} e lse {
_,err = app.DB.Exec(`UPDATE users SET data = $ 1 WHERE id = $ 2`,string(data),id)
}
check(err)
}

并且像这样调用它:

  u:= User {} 
a:=管理员{}

保存(u)
保存(a)






Effective Go


Getters



Go不为getter和setter提供自动支持。有
自己提供getter和setter没什么问题,而且
通常适合这样做,但是它不是习惯用法,也不需要
来获取getter的名字。如果您有一个名为owner
(小写,未导出)的字段,则应将getter方法称为Owner
(大写,已导出),而不是GetOwner。
导出的大写名称的使用提供了区分该字段与方法的钩子。如果需要,
setter函数可能会被称为SetOwner。两个名字
在练习中都很好的阅读:


  owner:= obj.Owner()
=用户{
obj.SetOwner(用户)
}



I have a gin-gonic web app with somewhat MVC architecture. I created a couple of models, all of them embed one common struct:

type User struct {
   ID int
   Name string
}

type Admin struct {
   User
   Level int
}

... {
   User
}

Now I want to store them in database in json format. The goal I want to accomplish is to code only one function/method that will marshal any model and will save save it into DB. This method must marshal all the fields of current model, not only from User struct, e.g. User must be marshaled into {id: 1, name: "zhora"}, while Admin will go into {id: 1, name: "gena", level: 2}.

Like this one:

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)
}

Right now I have to copy/paste this func to every model file, changing only method receiver. Can this be avoided?

解决方案

You may use one func Save(d interface{}) like this:

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)
}

output:

{"ID":0,"Name":""}
{"ID":0,"Name":"","Level":0}


for your case, use this one function for all types:

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)
}

And call it like this:

u := User{}
a := Admin{}

Save(u, u.ID)
Save(a, a.ID)


And Yes, this is even simplifies call to Save to one parameter:

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())
}

output:

{"Id":0,"Name":""}
ID is  0
{"Id":0,"Name":"","Level":0}
ID is  0


Now You may use this one function for all types:

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)
}

And call it like this:

u := User{}
a := Admin{}

Save(u)
Save(a)


Effective Go:

Getters

Go doesn't provide automatic support for getters and setters. There's nothing wrong with providing getters and setters yourself, and it's often appropriate to do so, but it's neither idiomatic nor necessary to put Get into the getter's name. If you have a field called owner (lower case, unexported), the getter method should be called Owner (upper case, exported), not GetOwner. The use of upper-case names for export provides the hook to discriminate the field from the method. A setter function, if needed, will likely be called SetOwner. Both names read well in practice:

owner := obj.Owner()
if owner != user {
    obj.SetOwner(user)
}

这篇关于一种处理所有嵌入一个公共结构(json编组)的结构类型的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆