Golang如何将interface{}转换为struct类型?

huangapple go评论78阅读模式
英文:

Golang convert interface{} to struct

问题

我想改进下面代码中的getCustomerFromDTO方法,我需要从interface{}创建一个struct,目前我需要将该interface序列化为byte[],然后再将数组反序列化为我的struct - 必须有更好的方法。

我的使用案例是通过rabbitmq发送structs,并且为了发送它们,我使用了这个通用的DTO包装器,其中包含有关它们的附加领域特定数据。
当我从rabbit mq接收DTO时,消息的下一层将被反序列化为我的DTO,然后我需要从该DTO中获取我的struct。

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{Data: 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
}
英文:

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

得分: 31

在解组装 DTO 之前,将 Data 字段设置为你期望的类型。

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

type UniversalDTO struct {
    Data interface{} `json:"data"`
    // 其他包含消息重要元数据的字段...
}

func main() {
    // 创建一个 Customer,将其添加到 DTO 对象并进行编组
    customer := Customer{Name: "Ben"}
    dtoToSend := UniversalDTO{Data: customer}
    byteData, _ := json.Marshal(dtoToSend)

    // 解组装(通常在从某处接收字节后进行)
    receivedCustomer := &Customer{}
    receivedDTO := UniversalDTO{Data: receivedCustomer}
    json.Unmarshal(byteData, &receivedDTO)

    // 完成
    fmt.Println(receivedCustomer)
}

如果在解组装 DTO 之前无法初始化 Data 字段,你可以在解组装后使用类型断言。encoding/json 包将 interface{} 类型的值解组装为 map[string]interface{},因此你的代码将如下所示:

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

type UniversalDTO struct {
    Data interface{} `json:"data"`
    // 其他包含消息重要元数据的字段...
}

func main() {
    // 创建一个 Customer,将其添加到 DTO 对象并进行编组
    customer := Customer{Name: "Ben"}
    dtoToSend := UniversalDTO{Data: customer}
    byteData, _ := json.Marshal(dtoToSend)

    // 解组装(通常在从某处接收字节后进行)
    receivedDTO := UniversalDTO{}
    json.Unmarshal(byteData, &receivedDTO)

    // 尝试从 DTO 中解组装我们的 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
}
英文:

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
}

huangapple
  • 本文由 发表于 2017年4月10日 22:00:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/43325288.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定