【问题标题】:How can I convert a JSON string to a byte array?如何将 JSON 字符串转换为字节数组?
【发布时间】:2022-03-06 05:15:55
【问题描述】:

我需要一些关于解组的帮助。我有这个示例代码:

package main

import (
    "encoding/json"
    "fmt"
)

type Obj struct {
    Id   string `json:"id"`
    Data []byte `json:"data"`
}

func main() {
    byt := []byte(`{"id":"someID","data":["str1","str2"]}`)

    var obj Obj
    if err := json.Unmarshal(byt, &obj); err != nil {
        panic(err)
    }

    fmt.Println(obj)
}

我在这里尝试做的 - 将字节转换为结构,其中一个字段的类型是 []byte。我得到的错误:

panic: json: cannot unmarshal string into Go struct field Obj.data 输入 uint8

这可能是因为解析器已经看到“数据”字段已经是一个切片并试图将“str1”表示为一些 char 字节码(类型 uint8?)。

如何将整个 data 值存储为一个字节数组?因为我想稍后将值解组到字符串切片。我没有将字符串切片包含在 struct 中,因为这种类型可以更改(字符串数组、int、字符串等),我希望这是通用的。

【问题讨论】:

  • 您正在呈现两个字符串并希望它们适合单个字节片?
  • 我希望整个 ["str1","str2"] 成为 []byte
  • 你的意思是你想让整个字符串 '["str1","str2"]' 成为一个 []byte?
  • 正确,与内容无关。它只是在这种特定情况下看起来像一个数组

标签: go


【解决方案1】:

如果您知道输入类型将是字符串数组,我的第一个建议是只使用 []string 而不是 []byte

如果data 将是一个具有各种类型的 JSON 数组,那么您最好的选择是改用 []interface{} - Go 会很乐意为您解组 JSON,您可以在运行时执行检查以将它们转换为更多根据需要的特定类型变量。

【讨论】:

  • 这实际上可能比在我的回答中使用json.RawMessage 更好。我想说这确实是应该做的,但我选择更具体地回答这个问题;)
【解决方案2】:

如果[]byte真的是你想要的,使用json.RawMessage,它类型[]byte,但也实现了JSON解析的方法。我相信这可能是您想要的,因为它会接受以data 结尾的任何内容。当然,您必须手动解析 Data 以找出其中实际存在的内容。

一个可能的好处是它跳过了任何繁重的解析,因为它只是复制了bytes。当您想将此数据用于某事时,您可以使用[]interface{},然后使用类型开关来使用各个值。

https://play.golang.org/p/og88qb_qtpSGJ

package main

import (
    "encoding/json"
    "fmt"
)

type Obj struct {
    Id   string          `json:"id"`
    Data json.RawMessage `json:"data"`
}

func main() {
    byt := []byte(`{"id":"someID","data":["str1","str2", 1337, {"my": "obj", "id": 42}]}`)

    var obj Obj
    if err := json.Unmarshal(byt, &obj); err != nil {
        panic(err)
    }

    fmt.Printf("%+v\n", obj)
    fmt.Printf("Data: %s\n", obj.Data)

    // use it
    var d []interface{}
    if err := json.Unmarshal(obj.Data, &d); err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", d)

    for _, v := range d {
        // you need a type switch to deterine the type and be able to use most of these
        switch real := v.(type) {
        case string:
            fmt.Println("I'm a string!", real)
        case float64:
            fmt.Println("I'm a number!", real)
        default:
            fmt.Printf("Unaccounted for: %+v\n", v)
        }

    }
}

【讨论】:

  • 可能不是,data 可以是任何东西 - 数组、字符串、int 等。在这种特定情况下,我希望 obj.Data 为 `["str1","str2"]` - 注意` char,所以这应该只是字节,而不是数组
  • 看起来很有趣! “RawMessage”类型不是比 interface{} 或 []byte 更昂贵吗? (只是问)
  • @Alexey 在回答中解决了这个问题并添加了RawMessage 的用法。
  • 如果您关心昂贵,那么 json 不是交换数据的一个很好的选择,因为 json 很昂贵,因为要进行所有转换和创建结构。看看协议缓冲区,它们旨在避免昂贵的 json 处理
  • 除非您实际上需要它是[]byte,否则@Venantius 有更好的答案。
【解决方案3】:

你的问题是:

将字节数组转换为具有 []byte 类型字段的结构

但是你没有字节数组而是字符串数组。您的问题与您的示例不同。因此,让我们回答您的问题,根据您希望偏离原始要求的程度,可能有更多解决方案。

一个字符串可以转换为一个字节片,需要先将两个字符串转换为一个字符串。所以这是问题一。第二个问题是你的 json-string 中的方括号

这很好用,它将 json-string 中的字符串隐式转换为字节片:

byt := []byte(`{"id":"someID","data":"str1str2"}`)

var obj Obj
if err := json.Unmarshal(byt, &obj); err != nil {
    panic(err)
}

fmt.Println(obj)

【讨论】:

  • 他不关心数组的内容。他希望整个事情都成为[]byte
  • 没错,在另一种情况下,它可能根本不是数组,而是其他东西,比如整数。因此,不要尝试查看[1,2],而是尝试查看 [5]byte,其中第一个和最后一个字节是方括号的字符
  • 我认为,在这种情况下,RayfenWindspear 的答案对你更有用,虽然它没有给你一个字节片。但是,如果您不关心这一点,那么 Venantius 的答案也是合适的并且更容易实现。我是在您最初问题的定义范围内回复的。
猜你喜欢
  • 2013-05-08
  • 2015-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
相关资源
最近更新 更多