【Golang】- []byte在结构体的友好可读性处理

前言

有些时候,我们会发现,[]byte 类型在 struct 中,是必不可少的结构体,因为用了[]byte代表可以存储字节数据,也可以叫做二进制安全的存储。代表可以存储任何数据。

如何才能做到在序列化json的情况下,可以Println出一个可读性的在struct[]byte呢?

实现

最近我在开发我们的部门的配置服务,需要提供一个配置工具。里面设计的一个struct,有一个[]byte类型,就是用来存储实际数据的。但是我们在这里的时候,我们有一个查看原始数据的需求,因为我们的数据经过了加密,和压缩,最终才会放到该结构体。

简化结构体,这里列举一下例子:

1
2
3
4
5
6
7
type V []byte

type Value struct {
PublishTime int64
PublishDateTime string
Value V
}

这里我们看到,我们这里的Value实际就是一个[]byte,我们把这个结构体经过json.Marshal之后推送到远端kv服务中,一切都正常。

但是当我们需要查看的时候,就需要从远端的kv拉回来,经过json.Unmarsha处理,这个时候,我们会发现:

1
{"PublishTime":1630636657,"PublishDateTime":"2021-09-03 02:37:37.8693941 +0000 UTC m=+0.015759101","Value":"MTIzCg=="}

这里,我们看到Value是一个经过base64加密过的数据,这是因为默认情况下[]byte将会把数据经过base64变成字符串来符合json数据类型。那么我们有什么版本让他显示出原来真是的数据呢?

这里我使用了一个方案,借助多一个数据结构,对T V进行一个重组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type VO []byte

type ValueReadable struct {
PublishTime int64
PublishDateTime string
Value VO
}

func (b *VO) MarshalJSON() ([]byte, error) {
return *b, nil
}

func (b *VO) UnmarshalJSON(input []byte) error {
*b = input
return nil
}

定义多一个大体上一致的结构体,注意此时的Value不再是V,而是VO,我们对VO自定义json序列化的行为,那就是把base64的行为给去掉。

这样子,我们得到的数据就会是

1
{"PublishTime":1630636657,"PublishDateTime":"2021-09-03 02:37:37.8693941 +0000 UTC m=+0.015759101","Value":123}

细心的朋友一定发现了问题所在,那就是ValueValueReadable怎么进行转换。

因为你存的时候是通过Value进行marshal的,那么你的unmarsha行为一定要对应才能解到正确的数据。

所以这里,就是我们的一个重点,我们需要借助unsafe.Pointer

1
2
3
4
5
6
7
8
9
10
11
      // because []byte in struct will be base64encode
// so you will see such as "Ik1USXpDZz09Ig=="
// we should base64decode, so we custom a struct do not base64encode
// struct type transform use unsafe.Pointer
p := unsafe.Pointer(&persistenceValue)
vr := (*config_sync.ValueReadable)(p)
tv, err := json.Marshal(vr)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(tv))

我们利用unsafe指针数据类型,进行一个强制转换,为什么会成功呢,因为在内存对齐的结构上,这2个对象的内存是一致的,所以我们就可以进行强制转换,而不用担心有panic的产生。这只是unsafe指针的一个灵活运用。但是可以达到我们的目的,十分的有效果。

1
{"PublishTime":1630636657,"PublishDateTime":"2021-09-03 02:37:37.8693941 +0000 UTC m=+0.015759101","Value":123}

转换后,就可以看到我原本的数据了 123.