【问题标题】:Golang JSON decoder does not recognize typeGolang JSON解码器无法识别类型
【发布时间】:2017-07-17 10:58:55
【问题描述】:

仍然是 Golang 初学者,我正在尝试编写一个通用函数来服务 ReST 请求。我传递了一个函数来创建一个新资源(结构),并在其上实现了一个接口,因为我还将调用结构上的方法。解码 JSON 时,记录类型显示正确的(结构)类型,但 JSON 解码器似乎只识别接口,它无法解码。

package main

import (
    "encoding/json"
    "github.com/julienschmidt/httprouter"
    "log"
    "net/http"
    "strings"
)

// general resource interface
type resource interface {
    // check semantics and return an array of errors or nil if no error found
    check() []string
    // update the resource in backend
    update() error
}

// specific resource named "anchor"
type anchor struct {
    ID   string `json:"id"`
    Name string `json:"name"`
}

func newAnchor() resource {
    return anchor{}
}

func (a anchor) check() []string {
    return nil
}

func (a anchor) update() error {
    return nil
}

// generic function to create (POST) a new resource
func restCreate(newResource func() resource) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
        const F = "restCreate"
        var checkErrs []string

        res := newResource()
        log.Printf("%s res type %T\n", F, res)
        dcdr := json.NewDecoder(r.Body)
        err := dcdr.Decode(&res)
        log.Printf("%s Unmarshalled into %T: %+v\n", F, res, res)
        if err == nil {
            checkErrs = res.check()
        }
        switch {
        case err != nil:
            w.WriteHeader(http.StatusInternalServerError)
            log.Printf("[ERR] %s: %v\n", F, err)
        case checkErrs != nil:
            w.WriteHeader(http.StatusBadRequest)
            w.Write([]byte(strings.Join(checkErrs, "\n")))
            log.Printf("%s: %v\n", F, err)
        default:
            res.update()
            bs, _ := json.Marshal(res)
            w.Write(bs)
        }
    }
}

func main() {
    r := httprouter.New()
    r.POST("/anchors", restCreate(newAnchor))
    http.ListenAndServe(":8080", r)
}

执行日志显示:

restCreate res type ma​​in.anchor
restCreate 解组到 main.anchor: {ID: Name:}
[ERR] restCreate: json: 无法将对象解组为 ma​​in.resource

类型的 Go 值

为什么 Printf 显示结构类型而 json.Decoder 显示接口?
我会很感激任何关于出了什么问题以及如何以通用方式解决这个问题的指标......

【问题讨论】:

    标签: json go


    【解决方案1】:

    这是因为您尝试使用指向接口的指针来解组。您需要在函数中返回一个指针

    func newAnchor() resource {
        return &anchor{}
    }
    

    而且您不需要在此行中获取地址: err := dcdr.Decode(&res)

    这是一个小的工作示例:https://play.golang.org/p/3E0RmGTURO

    【讨论】:

    • 这行得通 - 谢谢 Pavlo。有点困惑,为什么你可以同时返回组合文字和它的地址,将进一步探讨。
    【解决方案2】:

    除非变量持有指向您想要的具体类型的指针,否则您无法解组到接口中,因为json.Decode 不知道要使用哪种具体类型。您可以使用两种解决方法:

    newResource 在后台返回一个具体类型:

    func newResource() resource {
        return &anchor{}
    }
    

    这种方式json.Decode 知道将您的 JSON 解组为 anchor

    使用newAnchor 代替newResource:这将在您的restCreate 函数中更具可读性,并且更惯用[1]。

    [1]http://idiomaticgo.com/post/best-practice/accept-interfaces-return-structs/

    【讨论】:

    • 感谢您的回答。我想为许多不同的具体结构使用“restCreate”,但你的答案(和 Pavlo 的)解决了这个问题。
    • 在阅读了您提供的链接后,我认为作者正在争论我实现的确切解决方案 - 在底层具体类型上使用接口。再次感谢您提供的信息!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 2017-11-29
    • 1970-01-01
    • 2015-03-06
    相关资源
    最近更新 更多