DMa*_*yer 3 json dictionary marshalling go
说我有以下代码:
m := map[string]string{}
//... do stuff to the map
b, err := json.Marshal(m)
Run Code Online (Sandbox Code Playgroud)
在这种情况下有没有办法json.Marshal调用会返回错误?
我想知道是出于好奇,部分是考虑我是否需要担心错误检查.
由于任何有效值string都是有效密钥,而且JSON中的有效值(有关详细信息,请参阅JSON密钥名称中哪些字符有效/无效?),理论上它不会返回任何错误.
如果发生内存不足错误,json.Marshal()将无法返回,您的应用程序将以错误代码终止.
由于Go将string值存储为UTF-8编码的字节序列,因此存在无效的UTF-8编码字符串内容的问题.这也不会导致任何错误,因为Go将使用Unicode替换字符U + FFFD替换无效代码点,如下例所示:
m := map[string]string{"\xff": "a"}
data, err := json.Marshal(m)
fmt.Println(string(data), err)
Run Code Online (Sandbox Code Playgroud)
输出(在Go Playground上试试):
{"\ufffd":"a"} <nil>
Run Code Online (Sandbox Code Playgroud)
此行为记录在json.Marshal():
字符串值编码为强制为有效UTF-8的JSON字符串,用Unicode替换符号替换无效字节.
这可能是一个编组map[string]string绝不会返回一个错误,不过,你应该检查返回的错误,除非文档明确指出返回的error始终是nil(的文档json.Marshal()不会记录这样的行为).这种罕见的例子是rand.Read()其中记录了"它总是返回LEN(p)和一个零误差".
并且标准库也有可能存在错误,因此即使json包的实现可能无意在编组时返回任何错误map[string]string,但错误可能导致它仍然返回非nil错误.
另见相关问题:Go:json.Unmarshal什么时候会返回struct返回错误?
为了完整起见,让我们讨论json.Marshal()一下map[string]string在传递给它时可能导致失败的另一个问题.
Go 1.6在运行时添加了一个轻量级的并发滥用映射检测,你可以在这里阅读更多相关信息:如何从并发映射写入中恢复?
这意味着Go运行时可以检测是否在goroutine中读取或修改了映射,并且还同时修改了另一个goroutine,而没有同步.
所以这里的场景是我们传递map[string]string给json.Marshal().并且为了进行封送,json包必须显然迭代地图的键值.如果我们同时修改地图,那将导致失败.
这是一个激发它的示例代码(循环是为了增加并发修改的可能性,否则我们将在goroutine调度程序的手中):
m := map[string]string{"\xff": "a"}
go func() {
for i := 0; i < 10000; i++ {
m["x"] = "b"
}
}()
for i := 0; i < 10000; i++ {
if _, err := json.Marshal(m); err != nil {
panic(err)
}
}
Run Code Online (Sandbox Code Playgroud)
另请注意,在这种情况下json.Marshal()也不会返回(就像内存不足错误的情况一样),而是运行时会故意使应用程序崩溃.输出将是:
fatal error: concurrent map iteration and map write
Run Code Online (Sandbox Code Playgroud)