casting - 如何将未编码的 Golang 对象转换为指定变量的类型

标签 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
}

最佳答案

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

这本书不是作为 Book 存储的,而是作为 json 字符串存储的,json unmarshaller 不知道它是 Book,除非你告诉它。即它不知道将字段映射到 Book 对象。

你不能将未编码的“untyped”转换成一本书,因为它不是一本书,它是一个 map[string]interface{},恰好看起来完全像一本书。

你需要做的是

  1. 将 json 解码为 map[string]interface{},然后读取标题。
  2. 根据类型使用 if 语句或 switch 语句
  3. 再次将 json 解码为该类型的对象(例如,一本书)

我猜是这样的:

// 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
} 

关于casting - 如何将未编码的 Golang 对象转换为指定变量的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26567249/

相关文章:

c# - 如何向下转换通用类型的实例?

go - 解析时区为 “GMT+0000”的时间字符串时出错

c++ - 这个从 long in a union 到 char* 和 back 的转换是做什么的?

java - 在 Java 中使用什么数据结构来添加对象和使用 subList

在c中转换数据类型

c - 从假定相同尺寸的类型进行类型转换时发出警告

casting - 如何在数字类型之间进行转换?

docker - 在 dockerfile 中运行 go build main.go

go - 在 Go 中使用单独文件中定义的代码

postgresql - 从 hstore 中删除 key 时出现意外的字符串结尾