2016-08-24 112 views
1

我有一個帶有一些MVC體系結構的金湯匙web應用程序。我創建了幾個型號,他們都嵌入一個共同的結構:處理嵌入一個公共結構(json編組)的所有結構類型的一種方法

type User struct { 
    ID int 
    Name string 
} 

type Admin struct { 
    User 
    Level 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 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每一個模型文件,只改變方法接收機。這可以避免嗎?

回答

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) 

Effective Go

吸氣劑

Go不提供getter和setter自動支持。有 自己提供getter和setter沒什麼問題,它的 往往適合這樣做,但它既不是慣用的也不是必要的 把get進入getter的名字。如果您有一個名爲所有者 (小寫,未導出)的字段,則應將getter方法稱爲所有者 (大寫,已導出),而不是GetOwner。使用 導出的大寫名稱提供了區分字段和方法的鉤子。如果需要,setter函數可能會被稱爲SetOwner。兩個人的名字 在實踐中讀得好:

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

@kakysha我希望這有助於。 – 2016-08-24 20:13:02

+1

謝謝!非常感謝您的幫助。你的解決方案可以工作,但我進一步研究了一下,並用'getID()int'和'setID(int)'方法創建了一個'Model'接口,使得'User'滿足這個接口並使用'Model'而不是'interface {}'作爲方法'Save(m Model)'的參數不能傳遞id作爲第二個參數,只有結構本身。另外,我需要它在'INSERT ... RETURNING id'之後的傳遞結構上分配ID字段。再次感謝!,你救了我! – kakysha

+1

看到了關於getters和setter的更新。使User.ID導出並將getID()重命名爲ID(),再次感謝。出於某種原因'golint'沒有抱怨它:( – kakysha

相關問題