2014-01-30 54 views
3

看這個遊樂場:http://play.golang.org/p/dWku6SPqj5爲什麼json.Unmarshal返回一個映射而不是預期的結構?

基本上,我正在庫接收interface{}作爲參數,然後需要json.Unmarshal從字節數組。在封面之下,interface{}參數是一個匹配字節數組的json結構的結構,但是該庫沒有對該結構的引用(但它確實具有對相應的reflect.Type through的引用)。

爲什麼不能檢測基礎類型的json包?出於某種原因,它將返回一個簡單的地圖,而不是實際的結構。

下面的代碼:

package main 

import "fmt" 
import "encoding/json" 
import "reflect" 

func main() { 
    good() 
    bad() 
} 

func good() { 
    var ping Ping = Ping{} 
    deserialize([]byte(`{"id":42}`), &ping) 
    fmt.Println("DONE:", ping.ID) 
} 

func bad() { 
    var ping interface{} = Ping{} 
    deserialize([]byte(`{"id":42}`), &ping) 
    fmt.Println("DONE:", ping) // It's a simple map now, not a Ping. Why? 
} 

func deserialize(stuff []byte, thing interface{}) { 
    value := reflect.ValueOf(thing) 
    fmt.Printf("%+v | %v\n", value, value.Kind()) 

    err := json.Unmarshal(stuff, thing) 
    if err != nil { 
     panic(err) 
    } 
} 

type Ping struct { 
    ID int `json:"id"` 
} 

回答

3

你傳遞給json的指針抽象接口。您應該只是一個指針傳遞給Ping的抽象接口:

func bad() { 
    var ping interface{} = &Ping{} // <<<< this 
    deserialize([]byte(`{"id":42}`), ping) // << and this 
    fmt.Println("DONE:", ping) // It's a simple map now, not a Ping. Why? 
} 

但是,如果你說你沒有指針投噸的interface{},你可以用反映創建一個新的指針,反序列化到它,並將值複製回來:

func bad() { 
    var ping interface{} = Ping{} 
    nptr := reflect.New(reflect.TypeOf(ping)) 
    deserialize([]byte(`{"id":42}`), nptr.Interface()) 
    ping = nptr.Interface() 
    fmt.Println("DONE:", ping) // It's a simple map now, not a Ping. Why? 
} 
+0

這將工作,但我不能這樣做。該庫不知道更大的應用程序使用的基礎類型。 'ping'作爲'interface {}'接收,就是這樣。有任何想法嗎? – mdwhatcott

+0

你也許可以用'reflect'來告訴'interface {}'的底層類型,並創建一個代表它的指針的新'interface {}'。 –

+0

我很想看到這一點 - 關心修改操場示例併發布修改? – mdwhatcott

相關問題