如何将unmarshalled Golang对象转换为指定变量的类型

时间:2014-10-25 21:06:54

标签: casting go type-conversion unmarshalling

我希望将各种对象编组,然后解组它们,并通过获取被编组的变量类型将它们转换回原始类型。 关键是我想将未编组的对象转换为指定变量的类型,而不指定类型。

短伪码:

// Marshal this
item := Book{"The Myth of Sisyphus", "Albert Camus"}
// Then unmarshal and convert to the type of the item variable.
itemType := reflect.TypeOf(item)
newItem itemType = unmarshalledItem.(itemType)  // This is the problem.
fmt.Println("Unmarshalled is:", reflect.TypeOf(newItem)) // Should print *main.Book

完整代码:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
    "reflect"
)

type Book struct {
    Title  string
    Author string
}

func main() {
    // Create objects to marshal.
    book := Book{"The Myth of Sisyphus", "Albert Camus"}
    box := make(map[string]interface{})
    box["The Myth of Sisyphus"] = &book
    itemType := reflect.TypeOf(box["The Myth of Sisyphus"])
    fmt.Println("Book is:", itemType)

    // Marshal objects to file.
    err := Write(&book)
    if err != nil {
        fmt.Println("Unable to save store.", err)
        return
    }

    // Unmarshal objects from file.
    untyped := make(map[string]interface{})
    bytes, err := ioutil.ReadFile("store.txt")
    if err != nil {
        fmt.Println("Unable to load store.", err)
        return
    }
    err = json.Unmarshal(bytes, &untyped)
    if err != nil {
        fmt.Println("Err in store unmarshal.", err)
        return
    }

    // Get Title property of unmarshalled object,
    // and use that to get variable type from box map.
    for k, v := range untyped {
        if k == "Title" {
            itemTitle := v.(string)
            fmt.Println("Cast item having title:", itemTitle)
            targetType := reflect.TypeOf(box[itemTitle])
            fmt.Println("Type to cast to is:", targetType)
            // Convert untyped to targetType.
            // This is the problem.
            typed targetType = untyped.(targetType)
            fmt.Println("Unmarshalled is:", reflect.TypeOf(typed)) // Should print *main.Book
        }
    }
}

func Write(b *Book) error {
    data, err := json.Marshal(b)
    if err != nil {
        return err
    }
    newFilename := "store.txt"
    f, err := os.OpenFile(newFilename, os.O_CREATE|os.O_TRUNC, 0660)
    if err != nil {
        return err
    }
    _, err = f.WriteString(string(data) + "\n")
    if err != nil {
        return err
    }
    return nil
}

1 个答案:

答案 0 :(得分:1)

这可能适用于动态类型语言,但它不会在这里工作,因为Go是静态类型的。

这本书没有存储为Book,它存储为json字符串,json unmarshaller不知道它是一本书,除非你这么说。即它不知道将字段映射到Book对象。

你不能将未编组的'无类型'转换成一本书,因为它不是一本书,它是一个地图[string] interface {},它恰好看起来像一本书。

您需要做的是

  1. 将json解组为map [string] interface {},然后阅读标题。
  2. 使用if语句或基于类型的switch语句
  3. 再次将json解组为该类型的对象(例如一本书)
  4. 我猜是这样的事情:

    // check the type
    if targetType.String() == "*main.Book" {
        // unmarshall it again as a Book
        var typedBook Book
        _ = json.Unmarshal(bytes, &typedBook)
        fmt.Println("Unmarshalled is:", reflect.TypeOf(typedBook)) // Should print *main.Book
    } else if targetType.String() == "*main.Magazine" {
        // unmarshal a magazine or whatever
    }