【问题标题】:Unmarshaling JSON into a UUID type将 JSON 解组为 UUID 类型
【发布时间】:2021-12-07 05:32:31
【问题描述】:

我正在尝试使用 json.Unmarshaler 接口将 UUID 解组为结构上的 uuid.UUID 字段。我创建了一个名为 myUUID 的自定义类型,并且一切正常,直到我尝试访问通常在 uuid.UUID 上的方法。我该如何处理?我对 Go 比较陌生,所以也许我还没有完全理解自定义类型。

package main

import (
    "encoding/json"
    "errors"
    "fmt"

    "code.google.com/p/go-uuid/uuid"
)

var jsonstring = `
{
    "uuid": "273b62ad-a99d-48be-8d80-ccc55ef688b4"
}
`

type myUUID uuid.UUID

type Data struct {
    uuid myUUID
}

func (u *myUUID) UnmarshalJson(b []byte) error {
    id := uuid.Parse(string(b[:]))
    if id == nil {
            return errors.New("Could not parse UUID")
    }
    *u = myUUID(id)
    return nil
}

func main() {
    d := new(Data)
    err := json.Unmarshal([]byte(jsonstring), &d)
    if err != nil {
            fmt.Printf("%s", err)
    }
    fmt.Println(d.uuid.String())
}

【问题讨论】:

    标签: json go


    【解决方案1】:

    您可能希望确保您的 myuuid 变量在 Data struct: 中可见/导出:就像在“public”中一样。
    类型别名 MyUUID 相同(而不是 myUUID

    type MyUUID uuid.UUID
    
    type Data struct {
        Uuid MyUUID
    }
    

    来自JSON and Go

    json 包仅访问结构类型的导出字段(以大写字母开头的字段)。


    作为commented by Ainar Gstyle guide 也推荐:

    名称中的首字母缩写词或首字母缩略词(例如“URL”或“NATO”)的大小写一致。
    例如,“URL”应显示为“URL”或“url”(如“urlPony”或“URLPony”),而不应显示为“Url”。这是一个示例:ServeHTTP 不是 ServeHttp

    当“ID”是“标识符”的缩写时,此规则也适用于“appID”而不是“appId”。

    在你的情况下,这意味着:

    type Data struct {
        UUID MyUUID
    }
    

    【讨论】:

    • Uuid 也应该是 UUID。见the style guide
    • @Ainar-G 是真的。为了提高知名度,我已在答案中包含了该表扬。
    • 如果我想让uuid 成为私有属性,它应该命名为uUID?同样uRL, hTTPStatus?
    • @warvariuc no:uuid,httpStatus(大小写要一致),除了OP的情况,需要公开才能被JSON访问。
    • 我不是在谈论 JSON 案例,而是通常关于私有/公共属性。这气味。我认为将属性设为私有,通过在它们前面加上 _(就像在 Python 中一样)将是 Go 设计者的更好选择。
    【解决方案2】:

    Go 的自定义类型 don't inherit methods。我使用自定义结构重构了代码并附加了 UnmarshalJSON。

    import (
            "errors"
            "strings"
    
            "github.com/pborman/uuid"
    )
    
    
    type ServiceID struct {
        UUID uuid.UUID
    }
    
    type Meta struct {
        Name    string `json:"name"`
        Version string `json:"version"`
        SID     *ServiceID `json:"UUID"`
    }
    
    func (self *ServiceID) UnmarshalJSON(b []byte) error {
        s := strings.Trim(string(b), "\"")
        self.UUID = uuid.Parse(s)
        if self.UUID == nil {
                return errors.New("Could not parse UUID")
        }
        return nil
    }
    

    【讨论】:

    • 如何工作甚至编译? ServiceId类型中的UUID不是指针,那么if self.UUID == nil {怎么编译?
    • @emaborsa 因为uuid.UUID 实际上是[]byte 并且切片可以为零。见:github.com/pborman/uuid/blob/master/uuid.go#L32
    • 实际上我得到了两个编译错误。第一个cannot assign 2 values to 1 variablesParse,第二个cannot convert nil (untyped nil value) to uuid.UUIDself.UUID == nil。第一个可以通过添加第二个返回值来简单地修复,甚至可以像self.UUID, _ = uuid.Parse(s) 一样跳过它。其次,我必须将 UUID 属性定义为 UUID *uuid.UUID 之类的指针,但随后 Parse 的分配会报错。
    • @Emaborsa 我猜你正在使用的 UUID 包是 github.com/google/uuid,它确实从它的 Parse 函数返回了 2 个参数,并为 UUID 字节使用缓冲数组(不可为空) .但是,最初的问题是指code.google.com/p/go-uuid/uuid,现在是github.com/pborman/uuid,并且不会从Parse 返回error 值,而是使用无缓冲的字节片(可为空)。我将更新答案以包含所需的导入以支持答案,它确实可以编译。
    猜你喜欢
    • 1970-01-01
    • 2016-08-26
    • 1970-01-01
    • 2014-10-26
    • 2023-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-27
    相关资源
    最近更新 更多