为什么将JSON视为[]字节而不是字符串?

时间:2018-06-15 17:20:01

标签: json go

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

1 个答案:

答案 0 :(得分:12)

Go not go by"字符串用于文本,字节类型用于其他内容"像其他一些语言(例如Python 3)那样。 "In Go, a string is in effect a read-only slice of bytes." string类型附加了一些行为,这些行为对于处理UTF-8文本很方便,但它会保存您放入其中的任何字节。标准库中的文本处理内容经常被编写为与[]byte一起使用,例如package bytes镜像package stringsregexp两种交易。

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

为每个操作复制字符串内容会导致二次减速,因为字符串长度和副本数都随输入大小增长而增加。除了副本的直接成本之外,为它们分配空间使得垃圾收集更频繁地发生。出于这些原因,几乎所有通过Go中的大量小操作构建内容的内容都在内部使用[]byte。这包括JSON编组代码。这与JavaC#使用字符串构建器类的原因有关,现代JavaScript VM有一些聪明的技巧来推迟复制字节,直到经过一系列连续操作之后(更多内容,请阅读{{3 }和V8's cons strings)。

因为[]byte是读写的,而字符串是只读的,所以转换为另一个也必须复制字节。如果MarshalJSON返回string,则需要制作内容的另一个副本(以及GC上的相关负载)。此外,如果您最终要使用此操作进行I / O,Write()需要一个字节切片,因此您必须转换回来,创建另一个副本。所以它返回它内部构建的[]byte;如果您需要string(bytes)并且复制不是问题,您当然可以在结果上致电string

有点偏离原始问题的范围,但通常效果最佳的选项只是使用SpiderMonkey's ropes将输出直接流式传输到io.Writer。你从不必须一次分配整个输出块,并且它可以使你的代码更简单,因为没有临时变量你可以在一个中处理编组和I / O错误的地方。