Golang将空数组序列化/反序列化时不要作为null处理。

huangapple go评论81阅读模式
英文:

Golang serialize/deserialize an Empty Array not as null

问题

有没有一种方法可以序列化一个空数组属性(非空)的结构,并将其反序列化回一个空数组(再次非空)?

考虑到空数组实际上是指向null的指针,序列化/反序列化后,空数组和指向null的指针之间的可察觉的初始差异是否完全丢失?

最糟糕的实际情况是,当我将一个空数组属性显示给我的REST客户端时,作为一个json "att": [],第一次显示为空数组,然后在缓存注册到redis并恢复后,同样的属性显示给我的客户端为"att": null,导致合同破裂和很多困惑。

总结:是否可以在序列化/反序列化后,将Customer 2的地址显示为一个json空数组?

英文:

Is there a way to serialize an empty array attribute (not null) of a struct and deserialize it back to an empty array (not null again)?

Considering that an empty array is actually a pointer to null, is the perceptible initial difference between an empty array and pointer to null completely lost after serialize/deserialize?

The worst practical scenario is that when I show an empty array attribute to my REST client, as a json "att":[], at first time, and, after cache register to redis and recover it, the same attribute is shown to my client as "att":null, causing a contract broken and a lot of confusing.

Summing up: is possible to show the Customer 2 addresses like an json empty array, after serialize/deserialize => https://play.golang.org/p/TVwvTWDyHZ

答案1

得分: 18

我很确定你可以通过修改以下代码行来实现:

var cust1_recovered Customer

修改为:

cust1_recovered := Customer{Addresses: []Address{}}

除非我错误地理解了你的问题,我相信这是你期望的输出:

原始 Customer 2 {
  "Name": "Customer number 2",
  "Addresses": []
}
恢复后的 Customer 2 {
  "Name": "Customer number 2",
  "Addresses": []
}

你可以使用以下链接验证:https://play.golang.org/p/T9K1VSTAM0

需要注意的是,正如 @mike 指出的,如果 Addresses 在编码之前确实是 nil,那么在解码后,你将不会得到 JSON 中的 null,而是得到一个空列表。

英文:

I am pretty sure the easiest way you can do it is to change your line

var cust1_recovered Customer

to

cust1_recovered := Customer{Addresses: []Address{}}

Unless I am reading your question incorrectly, I believe this is your desired output:

ORIGINAL  Customer 2 {
  "Name": "Customer number 2",
  "Addresses": []
}
RECOVERED Customer 2 {
  "Name": "Customer number 2",
  "Addresses": []
}

Here is a playground to verify with: https://play.golang.org/p/T9K1VSTAM0

The limitation here, as @mike pointed out, is if Addresses is truly nil before you encode, once you decode you do not get the json equivalent null, but would instead end up with an empty list.

答案2

得分: 13

不,这是不可能的。为了理解为什么不可能,让我们看一下Go语言的规范。要使其在空数组和nil数组之间输出两个不同的结果,任何序列化方法都需要能够区分它们之间的差异。然而,根据Go语言的规范,

如果两个数组类型具有相同的元素类型和相同的数组长度,则它们是相同的。

由于两者都不包含任何元素并且具有相同的元素类型,唯一的区别可能在于长度,但规范还指出,

空切片、映射或通道的长度为0。

因此,通过比较,无法区分它们。当然,除了比较之外还有其他方法,所以为了确保这一点,以下是证明它们具有相同底层表示的部分。规范还保证了

如果结构体或数组类型不包含任何字段(或元素),其大小为零。

因此,长度为零的数组的实际分配结构大小必须为零。如果大小为零,它无法存储关于它是空还是nil的任何信息,因此对象本身也无法知道。简而言之,nil数组和长度为零的数组之间没有区别。

在序列化/反序列化过程中,“空数组和空指针之间的可察觉的初始差异”并没有丢失,而是从初始赋值完成的那一刻起就丢失了。

英文:

No, it's not possible. To understand why, let's look at the Go spec. For it to output two different results for empty vs. nil, any serialization method would need to be able to tell the difference between the two. However, according to the Go spec,

> Two array types are identical if they have identical element types and
> the same array length.

Since neither contains any elements and have the same element type, the only difference could be in length, but it also states that

> The length of a nil slice, map or channel is 0

So through comparison, it would be unable to tell. Of course, there are methods other than comparison, so to really put the nail in the coffin, here's the portion that shows they have the same underlying representation. The spec also guarantees that

> A struct or array type has size zero if it contains no fields (or
> elements, respectively) that have a size greater than zero.

so the actual allocated structure of a zero length array has to be of size zero. If it's of size zero, it can't store any information about whether it's empty or nil, so the object itself can't know either. In short, there is no difference between a nil array and a zero length array.

The "perceptible initial difference between an empty array and pointer to null" is not lost during serialization/deserialization, it's lost from the moment initial assignment is complete.

答案3

得分: 2

对于另一种解决方案,我们已经分叉编码/JSON来添加一个名为MarshalSafeCollections()的新方法。该方法将Slices/Arrays/Maps编组为它们各自的空值([]/{})。由于我们的实例化大部分发生在数据层,我们不想在HTTP响应层中添加修复问题的代码。对库的更改很小,并遵循Go版本发布。

英文:

For another solution, we have forked encoding/json to add a new method called MarshalSafeCollections(). This method will marshal Slices/Arrays/Maps as their respective empty values ([]/{}). Since most of our instantiation happens on the data layer we did not want to add code that fixed issues in our http response layer. The changes to the library are minimal and follow go releases.

huangapple
  • 本文由 发表于 2015年10月17日 13:21:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/33183071.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定