dsa5211314
2017-04-10 14:00
浏览 364
已采纳

Golang将接口{}转换为struct

I want to improve the getCustomerFromDTO method in the code below, I need to create a struct from an interface{} and currently i need to marshall that interface to byte[] and then unmarshal the array to my struct - there must be a better way.

My use case is that I send structs via rabbitmq and to send them I use this general DTO wrapper that has additional domain specific data about them. When I receive the DTO from rabbit mq one layer below the message is unmarshaled to my DTO and then i need to get my struct from that DTO.

type Customer struct {
    Name string `json:"name"`
}

type UniversalDTO struct {
    Data interface{} `json:"data"`
    // more fields with important meta-data about the message...
}

func main() {
    // create a customer, add it to DTO object and marshal it
    customer := Customer{Name: "Ben"}
    dtoToSend := UniversalDTO{customer}
    byteData, _ := json.Marshal(dtoToSend)

    // unmarshal it (usually after receiving bytes from somewhere)
    receivedDTO := UniversalDTO{}
    json.Unmarshal(byteData, &receivedDTO)

    //Attempt to unmarshall our customer
    receivedCustomer := getCustomerFromDTO(receivedDTO.Data)
    fmt.Println(receivedCustomer)
}

func getCustomerFromDTO(data interface{}) Customer {
    customer := Customer{}
    bodyBytes, _ := json.Marshal(data)
    json.Unmarshal(bodyBytes, &customer)
    return customer
}
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • duanji8887 2017-04-10 14:08
    已采纳

    Before unmarshaling the DTO, set the Data field to the type you expect.

    type Customer struct {
        Name string `json:"name"`
    }
    
    type UniversalDTO struct {
        Data interface{} `json:"data"`
        // more fields with important meta-data about the message...
    }
    
    func main() {
        // create a customer, add it to DTO object and marshal it
        customer := Customer{Name: "Ben"}
        dtoToSend := UniversalDTO{customer}
        byteData, _ := json.Marshal(dtoToSend)
    
        // unmarshal it (usually after receiving bytes from somewhere)
        receivedCustomer := &Customer{}
        receivedDTO := UniversalDTO{Data: receivedCustomer}
        json.Unmarshal(byteData, &receivedDTO)
    
        //done
        fmt.Println(receivedCustomer)
    }
    

    If you don't have the ability to initialize the Data field on the DTO before it's unmarshaled, you can use type assertion after the unmarshaling. Package encoding/json unamrshals interface{} type values into a map[string]interface{}, so your code would look something like this:

    type Customer struct {
        Name string `json:"name"`
    }
    
    type UniversalDTO struct {
        Data interface{} `json:"data"`
        // more fields with important meta-data about the message...
    }
    
    func main() {
        // create a customer, add it to DTO object and marshal it
        customer := Customer{Name: "Ben"}
        dtoToSend := UniversalDTO{customer}
        byteData, _ := json.Marshal(dtoToSend)
    
        // unmarshal it (usually after receiving bytes from somewhere)
        receivedDTO := UniversalDTO{}
        json.Unmarshal(byteData, &receivedDTO)
    
        //Attempt to unmarshall our customer
        receivedCustomer := getCustomerFromDTO(receivedDTO.Data)
        fmt.Println(receivedCustomer)
    }
    
    func getCustomerFromDTO(data interface{}) Customer {
        m := data.(map[string]interface{})
        customer := Customer{}
        if name, ok := m["name"].(string); ok {
            customer.Name = name
        }
        return customer
    }
    
    点赞 评论

相关推荐 更多相似问题