【问题标题】:How do I omit a struct field *only* when marshalling, but keep it when unmarshalling?如何在编组时省略结构字段 *only*,但在解组时保留它?
【发布时间】:2017-05-23 22:33:42
【问题描述】:

我有一个带有密码字段的用户结构。当我通过 POSTed JSON 创建用户(或使用新密码更新)时,我想将密码字段接受/解组到我的对象中,但是每当我 return 一个用户时,我想省略密码字段。以下是迄今为止我能想到的最好的。它有效,但它需要在我想消除的字段名称周围很多重复(现在,如果我添加一个像FirstName 这样的新字段,我必须在 3不同的地方)。

如何更好地做到这一点同时仍然尊重结构上的json 标签

func main() {
    origJson := []byte(`{"id":"1","username":"Chad","pwd":"sillypants"}`)
    fmt.Println("Original:     " + string(origJson))

    var unmarshalled User
    json.Unmarshal(origJson, &unmarshalled)
    fmt.Printf("Unmarshalled: %+v\n", unmarshalled)

    marshalled, _ := json.Marshal(unmarshalled)
    fmt.Println("ReMarshalled: " + string(marshalled))
}

type User struct {
    Id       string `json:"id"`
    Username string `json:"username"`
    Password string `json:"pwd"`
}

type SafeUser struct {
    Id       string `json:"id"`
    Username string `json:"username"`
}

func (u User) MarshalJSON() ([]byte, error) {
    safeUser := SafeUser{
        Id      : u.Id,
        Username: u.Username,
    }

    return json.Marshal(safeUser)
}

Try it 在 Go 游乐场

【问题讨论】:

    标签: json go marshalling unmarshalling


    【解决方案1】:

    利用embedded structs。定义一个用户,并将其嵌入到 UnsafeUser 中,该用户添加密码字段(以及其他任何内容,如付款信息)。

    type User struct {
        Id       string `json:"id"`
        Username string `json:"username"`
    }
    
    type UnsafeUser struct {
        User
        Password string `json:"pwd"`
    }
    

    (最好让事情默认安全并声明不安全的内容,例如Go's unsafe pacakge。)

    然后您可以从 UnsafeUser 中提取用户,而无需知道和复制所有字段。

    func (uu UnsafeUser) MarshalJSON() ([]byte, error) {
        return json.Marshal(uu.User)
    }
    
    $ go run ~/tmp/test.go
    Original:     {"id":"1","username":"Chad","pwd":"sillypants"}
    Unmarshalled: {User:{Id:1 Username:Chad} Password:sillypants}
    ReMarshalled: {"id":"1","username":"Chad"}
    

    请注意如何查看嵌入在未编组的 UnsafeUser 中的 User 结构。

    【讨论】:

    • 谢谢,这绝对比我的好!但是,我看到的问题是当手动实例化一个新的UnsafeUser...myUser := UnsafeUser{Id: "1", Username: "foo", Password: "bar"} 不起作用时,这意味着现在我的代码必须使用myUser := UnsafeUser{SafeUser: SafeUser{Id: "1", Username: "foo"}, Password: "bar"},这真是......太糟糕了。有什么办法吗?理想情况下,我希望其中 1 个类完全透明。
    【解决方案2】:

    我遇到了同样的问题,但遇到了this article

    这个想法是使用嵌入和匿名结构来覆盖字段。

    func (u User) MarshalJSON() ([]byte, error) {
        type Alias User
        safeUser := struct {
            Password string `json:"pwd,omitempty"`
            Alias
        }{
            // Leave out the password so that it is empty
            Alias: Alias(u),
        }
    
        return json.Marshal(safeUser)
    }
    

    Try it

    别名有助于防止编组时出现无限循环。

    请注意,您必须保持相同的 JSON 字段名称才能使覆盖生效。

    【讨论】:

    • 哦,这太完美了!并且别名在编组函数内是局部范围的,因此在其他任何地方都看不到或无法访问,使其完全透明。干得好!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 2020-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多