【问题标题】:Why does go treat JSON as []byte instead of string? [closed]为什么 Go 将 JSON 视为 []byte 而不是字符串? [关闭]
【发布时间】:2018-06-15 17:20:01
【问题描述】:

RFC 7159 说

JavaScript Object Notation (JSON) 是一种文本格式,用于 结构化数据的序列化。

但 Go 将 JSON 视为 []byte

func Marshal(v interface{}) ([]byte, error)
func Unmarshal(data []byte, v interface{}) error

为什么这些函数不接受并返回string

我在这里找不到任何解释 https://golang.org/pkg/encoding/json/ https://blog.golang.org/json-and-go

【问题讨论】:

  • 字符串在 Go 内部是一个 []byte,使用 raw 类型有一些效率优势。
  • 您在[]byte 切片中读取和写入数据,因此几乎在所有情况下都是这种类型。要求将数据转换为string 有什么意义?
  • 不久前有人问过类似的问题:stackoverflow.com/questions/10826651/…
  • 嗯,与其他问题的公认答案相比,我更符合 JimB 的评论。有很多地方适合字符串(映射键、配置的短字符串等或只读数据),但(可能令人困惑)它与您如何使用数据有关,而不是它是文本还是别的东西。
  • (我不同意对这个问题的反对意见——是的,它基于对应用于 Go 的错误字符串和文本的假设,但这是一个明确的问题,它可能对大家可以了解字符串和字节在 Go 中是如何工作的。)

标签: json go


【解决方案1】:

Go 确实 not 像其他一些语言(例如 Python 3)那样通过“字符串用于文本,字节类型用于其他东西”。 "In Go, a string is in effect a read-only slice of bytes." string 类型附加了一些行为,可以方便地处理 UTF-8 文本,但它会保存您放入其中的任何字节。标准库中的文本处理内容通常也可以与 []bytes 一起使用,例如package bytes mirrors package stringsregexp 都可以交易。

鉴于没有关于文本/二进制在语义上属于一种或另一种类型的规则,选择使用[]byte 可能是出于实际原因。由于字符串是只读字节切片,几乎所有更改字符串的操作都必须将字节复制到新字符串,而不是修改现有字符串。 (字符串切片是一个关键的例外;它只是创建一个新的字符串头,可以指向旧字符串的字节。)

为每个操作复制字符串内容会导致二次减速,因为字符串长度和副本数量都随着输入大小而增长。除了副本的直接成本之外,为它们分配空间会使垃圾收集更频繁地发生。由于这些原因,几乎所有通过 Go 中的许多小操作构建内容的东西在内部都使用 []byte。这包括 Go 的 JSON 编组代码,以及 Go 1.10 中添加的 strings.Builder 类。

(出于类似的原因,JavaC# 也提供字符串构建器类型,现代 JavaScript VM 有巧妙的技巧来推迟复制字节,直到经过一长串 concat 操作,例如 V8's cons strings 和 @987654329 @.)

因为[]bytes 是可读写的,而字符串是只读的,转换一个到另一个也必须复制字节。如果 MarshalJSON 返回 string,则需要制作另一个内容副本(以及 GC 上的相关负载)。此外,如果您最终要使用它进行 I/O,Write() 需要一个字节切片,因此您必须转换回来,创建另一个副本。 (为了稍微缓解这种情况,包括 *os.File 在内的一些 I/O 类型也支持 WriteString()。但并非全部都支持!)

因此,json.Encoder 返回它在内部构建的 []byte 更有意义;如果您需要 string 并且复制不是问题,您当然可以在结果上调用 string(bytes)

有点超出了原始问题的范围,但通常性能最佳的选项是使用json.Encoder 将输出直接流式传输到io.Writer。您永远不必一次分配整个输出块,它还可以使您的代码更简单,因为没有临时变量,您可以在一个地方处理编组和 I/O 错误。

【讨论】:

    猜你喜欢
    • 2015-03-18
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    • 2017-04-05
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    相关资源
    最近更新 更多