Golang - 通过接口传递2步的Unmarshal /重建对象

时间:2016-05-26 10:44:30

标签: object go interface

我和json和golang一起工作。我已经创建了一个TCP服务器,在解组所包含的数据之前,我需要解组消息以了解要求的服务类型。这有点难以解释所以这是我的代码:

package main

import (
    "fmt"
    "encoding/json"
)

type Container struct {
    Type string
    Object interface{}
}

type Selling struct {
    Surname string
    Firstname string
    //......
    Price int
}

type Buying struct {
    ID int
    Surname string
    Firstname string
    //..........
}

/*
type Editing struct {
    ID int
    ...............
}
Informations, etc etc
*/

func main() {

    tmp_message_json1 := Selling{Surname: "X", Firstname: "Mister", Price: 10}
    //tmp_message_json1 := Buying{ID: 1, Surname: "X", Firstname: "Mister"}
    tmp_container_json1 := Container{Type: "Selling", Object: tmp_message_json1}
    json_tmp, _ := json.Marshal(tmp_container_json1)

/*...........
We init tcp etc etc and then a message comes up !
...........*/

    c := Container{}
    json.Unmarshal(json_tmp, &c)
    //I unmarshal a first time to know the type of service asked

    //  first question: Does Unmarshal need to be used only one time?
    // does I need to pass c.Object as a string to unmarshal it in the called functions?
    if c.Type == "Buying" {
        takeInterfaceBuying(c.Object)
    } else if c.Type == "client" {
        takeInterfaceSelling(c.Object)
    } else {
        fmt.Println("bad entry")
    }
}

func takeInterfaceBuying(Object interface{}) {

    bu := Object

    fmt.Println(bu.Firstname, bu.Surname, "wants to buy the following product:", bu.ID)
}

func takeInterfaceSelling(Object interface{}) {

    se := Object

    fmt.Println(se.Firstname, se.Surname, "wants to sell something for:", se.Price)
}

我需要处理类似的消息,但我不知道它是否可能?有可能吗?

感谢您的帮助!

2 个答案:

答案 0 :(得分:6)

为此目的有json.RawMessage。

package main

import (
    "encoding/json"
    "fmt"
)

type Container struct {
    Type   string
    Object json.RawMessage
}

type Selling struct {
    Surname   string
    Firstname string
    Price     int
}

type Buying struct {
    ID        int
    Surname   string
    Firstname string
}

func main() {
    rawJson1 := []byte(`{"Type":"Selling","Object":{"Surname":"X","Firstname":"Mister","Price":10}}`)
    rawJson2 := []byte(`{"Type":"Buying","Object":{"ID":1,"Surname":"X","Firstname":"Mister"}}`)

    processMessage(rawJson1)
    processMessage(rawJson2)
}

func processMessage(data []byte) {
    var c Container
    json.Unmarshal(data, &c)

    switch {
    case c.Type == "Buying":
        processBuying(c)
    case c.Type == "Selling":
        processSelling(c)
    default:
        fmt.Println("bad entry")
    }
}

func processBuying(c Container) {
    var bu Buying
    json.Unmarshal(c.Object, &bu)
    fmt.Println(bu.Firstname, bu.Surname, "wants to buy the following product:", bu.ID)
}

func processSelling(c Container) {
    var se Selling
    json.Unmarshal(c.Object, &se)
    fmt.Println(se.Firstname, se.Surname, "wants to sell something for:", se.Price)
}

答案 1 :(得分:2)

我可能错了,但我认为你不能一步到位。

第一个想法:在map [string] interface {}

中解组

不要使用带有unmarshal的类型,而是使用map[string]interface{},然后从此地图构建销售/购买(或直接使用地图)

type Container struct {
    Type string
    Object map[string]interface{}
}

第二个想法:两步/无能容器

首先:在一个不知道类型

的无知容器中解组
type CluelessContainer struct {
    Type string 
    Object interface{} `json:"-"` // or just remove this line ?
}

然后在类型识别容器中解组。您可以使用工厂模式来提供正确的结构。