【问题标题】:Returning JSON structs of different types, dynamically?动态返回不同类型的 JSON 结构?
【发布时间】:2016-04-11 16:03:30
【问题描述】:

我正在玩 Go,并且在将我从其他语言的一些“继承”设计适应它的结构时遇到了麻烦。我用 OCaml 和其他一些具有类似结构的语言进行了编码,但我很困惑。如果没有类型继承,使用共享结构从不同位置返回 JSON 会变得有点奇怪。

我必须根据需要递归遍历输入数据以构建单个 JSON 对象以进行响应。

举个例子:

{
    "appVersion": "1.0.0",
    "messageStatus": "received"
}

...和:

{
    "appVersion": "1.0.0",
    "uploadStatus": "received"
}

到目前为止,我能找到在 Go 中完成这项工作的唯一方法是将包含“appVersion”的基本结构分别复制并粘贴到两个输出生成函数中,但我不想这样做,因为我没有'不想必须维护同一组代码两次。

这是我试图解决这个问题的地方:

type JSONResponse struct {
    appVersion string
}
type MessageJSONResponse struct {
    JSONResponse
    messageStatus string
}
type UploadJSONResponse struct {
    JSONResponse
    uploadStatus string
}

...然后:

type Message struct {
    formattingVersion *int

}

func NewMessageObject(r *http.Request) (bool, *MessageJSONResponse) {
    message := new(Message)

    if (true) {
        // #TODO: INSERT LOGIC HERE!
        *message.formattingVersion = 2;

    }

    if (message.formattingVersion != nil) {
        response := new(MessageJSONResponse)
        response.messageStatus = "OK"

        return false, errorResponse

    }

    return true, nil

}

...还有:

func init() {
    http.Handle("/endpoints/message", JSONResponseHandler(messageHandler))

}

func JSONResponseHandler(h func (w http.ResponseWriter, r *http.Request) interface {}) http.Handler {

// #TODO - convert `JSONResponse` into actual JSON or output JSON Error!

}

func messageHandler(w http.ResponseWriter, r *http.Request) JSONResponse { // #BROKEN TYPES?

    hasError, messageResponse := NewMessageObject(r)
    if (hasError || messageResponse==nil) { return nil } // #TODO
    ////

    // #TODO ... more message things.

    return messageResponse;

};

这种方法(对不起,任何代码错误,真的很长,我要去睡觉了)不起作用,因为为了传递不同的返回值......类型不能改变,等等。

JSONResponseHandler 包装器方法实际上适用于我,但仅适用于 interface {} 类型,考虑到类型的变化......所以我把它省略了,因为它会混乱编码。但是,如果我在带有可选星号返回属性(例如“NewMessageObject”)的后续块上使用interface {},JSON 构造函数似乎会忽略这些值,因为它们被包装在一个空接口中,而不是仅仅作为它们的原始类型公开。但是,他们必须有一个 nil 选项....

怎么了?一般的设计? 我基本上是在尝试通过基于输入数据的后续调用以一种简洁抽象的方式构建 JSON 对象响应(或返回 JSON 格式的错误)。

【问题讨论】:

    标签: json go


    【解决方案1】:

    要解决您的 json 问题,您可以使用一个结构并用 json:"omitempty" 标记每个字段:

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type foostruct struct {
        Myfoo   string `json:"myfoo,omitempty"`
        Yourfoo string `json:"yourfoo,omitempty"`
        Ourfoo string `json:"ourfoo,omitempty"`
    }
    
    func main() {
        j := []byte("{\"myfoo\":\"mine\", \"yourfoo\":\"yours\"}")
        fstruct := &foostruct{}
        err := json.Unmarshal(j, fstruct)
        if err != nil {
            panic(err)
        }
    
        b, err := json.Marshal(fstruct)
        if err != nil {
            panic(err)
        }
    
        fmt.Println(string(b))
    }
    

    您会看到输出不包含字段“ourfoo”:

    {"myfoo":"mine","yourfoo":"yours"}
    

    在这里试试: http://play.golang.org/p/zKwFaxbLJu

    【讨论】:

    • 嗯。这更像是一种解决方法而不是解决方案。您仍然必须提前在单个结构中定义所有可能的属性及其类型,不是吗?
    【解决方案2】:

    我在我的应用程序中使用 map 而不是 struct,尤其是当我想向客户端返回 json 答案时。它给了我更多的灵活性。请看这个:

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    func main() {
        m := make(map[string]interface{})
        m["appVersion"] = "0.0.1"
        m["uploadStatus"] = "success"
    
        strJson, _ := json.Marshal(m)
        str := string(strJson)
        fmt.Println("---ENCODING--")
        fmt.Println(str)
    
        //put it back
        fmt.Println("---DECODING--")
        n := make(map[string]interface{})
        json.Unmarshal([]byte(str), &n)
        for key, val := range n {
            fmt.Println(key, ":", val)
        }
    }
    

    输出是:

    ---ENCODING--
    {"appVersion":"0.0.1","uploadStatus":"success"}
    ---DECODING--
    appVersion : 0.0.1
    uploadStatus : success
    

    您可以在这里查看:http://play.golang.org/p/h4b4-nkZ4M

    【讨论】:

    • 那么,有没有一种简洁的方法来递归对象自己的层次结构或通过其子对象来创建映射树?或者您是否依赖于抽象字符串而不是编译器可以捕获错误的 struct var 名称?
    • 你的意思是递归到结构上的每个字段吗?是的,可以使用反射。对不起,其实我真的不明白你想达到什么目的?而你需要远离的是Golang上的面向对象的东西,它不适合Golang,你必须在界面上玩
    猜你喜欢
    • 1970-01-01
    • 2013-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    相关资源
    最近更新 更多