2016-04-07 21 views
0

Json ile kodlama/kod çözme yaparken özel yapıları serileştirmenin bir yolu var mı? Golang özel JSON serileştirme (json için gob.register() öğesine eşdeğer bir şey var mı?)

UDP üzerinden gönderilen ediliyor farklı özel yapılar (10 vardır benim gerçek kodda) Eğer 3 söylüyorlar ve kodlama için json kullanın: Eğer bilmek istiyorum alıcı olarak ucunda

type a struct { 
    Id int 
    Data msgInfo 
} 

type b struct { 
    Id  int 
    Data  msgInfo 
    Other metaInfo 
} 

type c struct { 
    Other metaInfo 
} 

Elde edilen yapı, a, b veya c tipindeydi, bu nedenle örneğin belirli bir kanala geçirilebilir. bahriyeli ile

type msgtype reflect.Type 

. 
. 

nrOfBytes, err := udpConn.Read(recievedBytes) 
if err != nil {...} 

var msg interface{} 
err = json.Unmarshal(recievedBytes[0:nrOfBytes], &msg) 
if err != nil {...} 

u := reflect.ValueOf(msg) 
msgType := u.Type() 
fmt.Printf("msg is of type: %s\n", msgType) 

bu kolayca türlerini kayıt yapılır, ama json o UDP üzerinden iletişim var gibi görerek kullanmak zorunda olduğu, bu nedenle özel yapılar seri hale getirmek zaten var mı? Ben baskı

msg is of type: a 

olmak istiyorum ama sadece yorumunuza

msg is of type: map[string]interface {} 
+0

için bu oyun örneğe bakın:

Örneğin (hata denetimi atlayarak)? Bir tür ile son bir noktaya dikkat etmenizi öneririm, böylece ne beklediğinizi zaten biliyorsunuzdur. O zaman bir REST API var diyelim/her şey POST için bir yapılandırma – nvcnvn

+0

ayrıştırmalıyım ne ben paketlenmiş denilen bir tür "Packet" gönderdiğimi paketlemeyi denedim, bu yüzden sadece bir "Veri" ile bu tür gönderilen ve aldım "özel yapıyı tutan alan. Ne yazık ki hiçbir şey değişmedi –

cevap

2

Yapabileceğiniz tek şey, json.RawMessage türünü ve özel bir Sarmalayıcı türünü kullanmaktır. Daha sonra, bir mesaj aldıktan sonra, doğru yapıyı almak için bir anahtar (veya bir kurucu haritasının kullanımı) yapabilirsiniz.

package main 

import ( 
    "encoding/json" 
    "fmt" 
)   

type Message struct { 
    Type string 
    Data json.RawMessage 
}   

func (m Message) Struct() interface{} { 
    unmarshaller, found := unmarshallers[m.Type] 
    if !found { 
     return nil 
    }  
    return unmarshaller([]byte(m.Data)) 
}   

type Foo struct { 
    ID int 
}   

var unmarshallers = map[string]func([]byte) interface{}{ 
    "foo": func(raw []byte) interface{} { 
     var f Foo 
     json.Unmarshal(raw, &f) 
     return f 
    },  
}   

func main() { 
    var body = []byte(`{"Type":"foo","Data":{"ID":1}}`) 
    var msg Message 
    json.Unmarshal(body, &msg) 

    switch s := msg.Struct().(type) { 
    case Foo: 
     fmt.Println(s) 
    }  
} 

canlı bir demo göndermek/Bir mesaj alma nasıl http://play.golang.org/p/7FmQqnWPaE

+0

teşekkür ederim, unmarshellers değişken harika çalışıyor! –

0

Base alıyorum, bu belki bir çözüm:

type Packet { 
    Type string 
    Data []byte 
} 

Encode fonksiyonu:

func packageEncode(i interface{}) ([]byte, error) { 
    b, err := json.Marshal(i) 
    if err != nil { 
    return nil, err 
    } 

    p := &Package{Data: b} 
    switch t.(type) { 
    case a: 
     p.Type = "a" 
    case b: 
     p.Type = "b" 
    case c: 
     p.Type = "c" 
    } 
    return json.Marshal(p) 
} 

Sonra, ne zaman alınan mesaj ve kod çözme:

p := &Package{} 
err = json.Unmarshal(recievedBytes[0:nrOfBytes], p) 
... 
if p.Type == "a" { 
    msg := &a{} 
    err = json.Unmarshal(p.Data, msg) 
} 

if p.Type == "b" { 
    ... 
} 
+0

cevabınız için teşekkürler :) –