无法将json.RawMessage进行编组,而[]byte可以正常工作。

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

Not able to marshal json.RawMessage while []byte works fine

问题

以下是翻译好的内容:

一个可复现的示例可以在这里找到:https://go.dev/play/p/wNyhezDfxVt

我想要使用json.Marshal(...)来编组一个包含json.RawMessage字段的结构体。

type Container1 struct {
	OldValue json.RawMessage `json:"old"`
	NewValue json.RawMessage `json:"new"`
}

然而,它报告了以下错误:

error calling MarshalJSON for type json.RawMessage: invalid character 'h' looking for beginning of value

json.RawMessage更改为[]byte可以解决此问题,但请注意,json.RawMessage实际上就是[]byte

// RawMessage是一个原始编码的JSON值。
// 它实现了Marshaler和Unmarshaler接口,可以用于延迟JSON解码或预先计算JSON编码。
type RawMessage []byte

我仍然希望能够使用json.RawMessage,有什么帮助吗?谢谢!

英文:

A reproducible example can be found here https://go.dev/play/p/wNyhezDfxVt

I want to marshal (json.Marshal(...)) a struct with json.RawMessage fields.

type Container1 struct {
	OldValue json.RawMessage `json:"old"`
	NewValue json.RawMessage `json:"new"`
}

However, it complains about the below error:

error calling MarshalJSON for type json.RawMessage: invalid character 'h' looking for beginning of value

Changing json.RawMessage to []byte fix the issue, but note that json.RawMessage is nothing but []byte:

// RawMessage is a raw encoded JSON value.
// It implements Marshaler and Unmarshaler and can
// be used to delay JSON decoding or precompute a JSON encoding.
type RawMessage []byte

I want to be still able to use json.RawMessage, any help? Thanks!

答案1

得分: 3

json.RawMessage类型被期望保存有效的JSON,因为它将按原样(raw)序列化。

当你使用[]byte("hello")初始化一个json.RawMessage字段时,你将字符串字面量"hello"转换为[]byte类型,其内容为hello(没有引号)。然后json.Marshal失败,因为你需要引号"使其成为有效的JSON字符串。要保留引号,你需要使用用反引号括起来的未转义的字符串字面量。

将你的结构体初始化更改为以下内容即可正常工作:

c1 := Container1{
	[]byte(`"hello"`),
	[]byte(`"world"`),
}

Container2中的[]byte切片不会引起错误,尽管它们保存了相同的字节内容,这是因为json.Marshal默认将字节切片序列化为base64编码。

事实上,在修复你的代码后,两个输出的JSON看起来是不同的:

使用json.RawMessage

{"old":"hello","new":"world"}

使用[]byte

{"old":"aGVsbG8=","new":"d29ybGQ="}
英文:

The type json.RawMessage is expected to hold valid JSON, because it will be serialized as-is (raw).

When you initialize a json.RawMessage field with []byte("hello"), you're converting to []byte, the string literal "hello", whose content is hello without quotes. Then json.Marshal fails, because you need the quotes " for it to be a valid JSON string. To keep the quotes, you have to use an unescaped string literal enclosed in backticks.

Changing the initialization of your struct to this will work:

	c1 := Container1{
		[]byte(`"hello"`),
		[]byte(`"world"`),
	}

The []byte slice in Container2 instead doesn’t cause errors despite holding the same byte content simply because json.Marshal defaults to serializing byte slices as base64.

As a matter of fact, after fixing your playground, the two output JSON look different:

From json.RawMessage:

{"old":"hello","new":"world"}

From []byte:

{"old":"aGVsbG8=","new":"d29ybGQ="}

huangapple
  • 本文由 发表于 2022年7月4日 16:43:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/72853941.html
匿名

发表评论

匿名网友

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

确定