2017-07-17 86 views
1

Golang初學者,我試圖編寫一個通用函數來服務ReST請求。我傳遞一個函數來創建一個新的資源(結構),其上實現了一個接口,因爲我也會調用結構體上的方法。在解碼JSON時,記錄類型顯示正確的(結構)類型,但JSON解碼器似乎只識別它無法解碼的接口。Golang 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 類型main.anchor
restCreate解組成main.anchor:{ID:名稱:}
[ERR] restCreate:JSON:不能解組object into Go值main.resource

爲什麼printf顯示結構體類型和json.Decoder的接口?
我會很感激在什麼地方出了錯,以及如何在一個通用的方法來解決這個任何指標...

回答

2

這是因爲你嘗試使用指針接口來解組。你需要在功能

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

返回一個指針,你並不需要在此行中獲得地址: err := dcdr.Decode(&res)

這裏是小工作示例:https://play.golang.org/p/3E0RmGTURO

+0

這工作 - 謝謝帕夫洛。只是有點困惑,爲什麼你可以返回合成文字和它的地址,將進一步探索。 – mhcbinder

0

除非變量持有一個指向你想要的具體類型,如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/

+0

謝謝您的回答。我想爲一些不同的具體結構使用「restCreate」,但你的回答(和Pavlo's)解決了這個問題。 – mhcbinder

+0

在閱讀您提供的鏈接後,我認爲作者正在爭論我實現的確切解決方案 - 在基礎具體類型上使用接口。再次感謝您提供的信息! – mhcbinder