为什么Go和Rust的序列化结果不一致?

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

Why are the results of Go and Rust serialization inconsistent?

问题

我想要的结果如下,但 Rust 的结果是另外一个。

[123 34 66 111 100 121 34 58 34 97 71 86 115 98 71 56 61 34 125]

Golang 示例:

type Response struct {
	Body    []byte
}
func Test_Marshal(t *testing.T)  {
	body := "hello"
	resp := &Response{
		Body:[]byte(body),
	}
	t.Log("resp:", resp)
	result, _ := json.Marshal(resp)
	t.Log("result: ", result)
}

Golang 结果:

    aa_test.go:17: resp: &{[104 101 108 108 111]}
    aa_test.go:19: result:  [123 34 66 111 100 121 34 58 34 97 71 86 115 98 71 56 61 34 125]

Rust 示例:

use serde_json::{Result, Value};
use serde::Serialize;

#[derive(Serialize, Debug)]
pub struct Response {
    pub body: ::std::vec::Vec<u8>,
}

fn main() {
    let body_str = "hello".to_string();
    let resp = Response {
        body: Vec::from(body_str)
    };

    println!("resp: {:?}", resp);

    let result = serde_json::to_vec(&resp).unwrap();
    println!("result: {:?}",result)
}

Rust 结果:

resp: Response { body: [104, 101, 108, 108, 111] }
result: [123, 34, 98, 111, 100, 121, 34, 58, 91, 49, 48, 52, 44, 49, 48, 49, 44, 49, 48, 56, 44, 49, 48, 56, 44, 49, 49, 49, 93, 125]

英文:

The results I want are as follows, but the result of Rust is another.

 [123 34 66 111 100 121 34 58 34 97 71 86 115 98 71 56 61 34 125]

golang sample:

type Response struct {
	Body    []byte
}
func Test_Marshal(t *testing.T)  {
	body := &quot;hello&quot;
	resp := &amp;Response{
		Body:[]byte(body),
	}
	t.Log(&quot;resp:&quot;, resp)
	result, _ := json.Marshal(resp)
	t.Log(&quot;result: &quot;, result)
}

go result:

    aa_test.go:17: resp: &amp;{[104 101 108 108 111]}
    aa_test.go:19: result:  [123 34 66 111 100 121 34 58 34 97 71 86 115 98 71 56 61 34 125]

rust sample:

use serde_json::{Result, Value};
use serde::Serialize;

#[derive(Serialize, Debug)]
pub struct Response {
    pub body: ::std::vec::Vec&lt;u8&gt;,
}

fn main() {
    let body_str = &quot;hello&quot;.to_string();
    let resp = Response {
        body: Vec::from(body_str)
    };

    println!(&quot;resp: {:?}&quot;, resp);

    let result = serde_json::to_vec(&amp;resp).unwrap();
    println!(&quot;result: {:?}&quot;,result)
}

rust result

resp: Response { body: [104, 101, 108, 108, 111] }
result: [123, 34, 98, 111, 100, 121, 34, 58, 91, 49, 48, 52, 44, 49, 48, 49, 44, 49, 48, 56, 44, 49, 48, 56, 44, 49, 49, 49, 93, 125]

答案1

得分: 5

如果我们将你的两个输出从字节数组转换为ASCII字符串(我使用了一个简单的JavaScript代码 - array.map(ch => String.fromCharCode(ch)).join("")),我们将得到以下结果:

// for Rust
{"body":[104,101,108,108,111]}
// for Go
{"Body":"aGVsbG8="}

因此,有两个不同之处:

  • 第一个也是最明显的区别是字段命名。两个序列化器都将字段名保留在JSON中,就像在源代码中一样,在Go中是Body(大写),而在Rust中是body(小写)。
  • 第二个区别是Rust将值按原样编码 - 即字节数组被视为数字的向量(它不会得到任何特殊处理)。然而,在Go中,它被转换为Base64字符串 - 这是一个明确记录的例外情况,可能是因为在大多数情况下这是预期的行为。

现在,要做什么取决于您想要使用的行为。我不知道如何更改Go的输出,所以我假设它是正确的,而Rust的输出需要进行调整。

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Response {
    #[serde(with="base64")]
    pub body: Vec<u8>,
}

mod base64 {
    use serde::{Serialize, Deserialize};
    use serde::{Deserializer, Serializer};

    pub fn serialize<S: Serializer>(v: &Vec<u8>, s: S) -> Result<S::Ok, S::Error> {
        let base64 = base64::encode(v);
        String::serialize(&base64, s)
    }
    
    pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<u8>, D::Error> {
        let base64 = String::deserialize(d)?;
        base64::decode(base64.as_bytes())
            .map_err(|e| serde::de::Error::custom(e))
    }
}
英文:

If we convert both your outputs from byte arrays to ASCII strings (I've used a simple Javascript code - array.map(ch =&gt; String.fromCharCode(ch)).join(&quot;&quot;)), we'll get the following:

// for Rust
{&quot;body&quot;:[104,101,108,108,111]}
// for Go
{&quot;Body&quot;:&quot;aGVsbG8=&quot;}

So, there seem to be two differences:

  • The first and the most obvious is the fields naming. Both serializers leave the field name in JSON as it was in the source code, so in Go it is Body (capitalized), while in Rust it is body (lower-case).
  • The second is that Rust encodes the value as-is - i.e. the byte array is treated as a vector of numbers (it doesn't get any special treatment). In Go, however, it is converted to Base64 string - this is an explicitly documented exception, probably because in most cases this is the intended behavior.

Now, what to do here? It depends on what behavior you want to use. I don't know how to change output with Go, so I assume that it is correct, and the Rust one needs to be tweaked.

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Response {
	#[serde(with=&quot;base64&quot;)]
	pub body: Vec&lt;u8&gt;,
}

mod base64 {
    use serde::{Serialize, Deserialize};
    use serde::{Deserializer, Serializer};

    pub fn serialize&lt;S: Serializer&gt;(v: &amp;Vec&lt;u8&gt;, s: S) -&gt; Result&lt;S::Ok, S::Error&gt; {
        let base64 = base64::encode(v);
        String::serialize(&amp;base64, s)
    }
    
    pub fn deserialize&lt;&#39;de, D: Deserializer&lt;&#39;de&gt;&gt;(d: D) -&gt; Result&lt;Vec&lt;u8&gt;, D::Error&gt; {
        let base64 = String::deserialize(d)?;
        base64::decode(base64.as_bytes())
            .map_err(|e| serde::de::Error::custom(e))
    }
}

huangapple
  • 本文由 发表于 2021年12月27日 14:25:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/70492295.html
匿名

发表评论

匿名网友

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

确定