Skip to content

20201205关于encoding.binary hex json的探讨

ziyouzy edited this page Dec 5, 2020 · 1 revision

首先,无论是堆还是栈,当你拿到了一个变量,他是一个最为原始的Raw状态

有人说这个raw是二进制状态,其实也不完全正确,因为1010101的二进制包含了大端与小端两种协议形式

总的来说,raw类似于一种“模因”层面的无法描述的状态,但是这种状态虽然无法描述但是可以通过不同的协议(encodeing)转换,转换后就变成了可以被人或机器描述于识别的形式

golang以及任何语言往往都会隐式实现一个简单的转换,比如拿到一个byte数组、切片、缓冲器(字节流容器),都是默认实现了了二进制大端序协议的,而这不是为了让程序员方便阅读,而是让机器方便

而如果想让人来读懂,其实正是fmt.Println()方法的意义所在

而各种原始数据类型,如string,int,float,也都是将raw通过各个协议(比如int协议、float协议)转换后的结果

这里需要注意的是,int之类的其实机器是没法读懂的,只是为了提高变成效率,而为程序员准备的一种“临时状态”,而各种ide以及开发环境的“编译”事件,就是为了将所由这些“临时状态”统一转化为“二进制大端序协议”从而让机器读懂,从而让机器可以直接运行你的程序

而有些时候程序员为了实现某种需求必须主动去将一些复杂数据类型转化为“二进制大端序协议”,这些需求包括但不限于“网络通信相关的socket数据传输、读取io文件时的一些操作环节、等”

这时就需要binary包了,其实就是将string、int、float以及其他的形式显式转换成“二进制大/小端序协议”,从而方便后续的操作

想到这里就可以明白,physiaclnode结构体虽然接近底层,但是在逻辑上其内部的字段应该存在各个已经实现转换的数据类型,比如string DI1这些,因为通过socket拿到一个“二进制大端序协议字节序"后,第一件事就是应该将他转化成上面所说的“临时状态”,从而方便之后的编程操作,physicalnode的意义只在于拿到无状态的节点信息,同时也应该为后续的操作准备好各个不同的“临时状态”,如int64形式的时间戳,string形式的诸如DO1这样的节点值

接下来再去聊聊hex包,或者说是十六进制协议,16进制数其实本质上也是不能被计算机读取的,或者说,不能被计算机的cpu读取,但是他在编程世界的地位也是一种“临时状态”,同时他也是整形(int)的一种子类型。

binary包里提供了方法可以将一个raw转化成整形,从而方便放入一个int的“容器”(数据类型)里,从而完成一个raw到一个“临时状态”的转换。

而并没有提供将一个raw转化成一个16进制整形,或者说不该存raw转化成一个16进制整形这种事件。

而hex包的存在其实面向的是程序员或者人类,hex包内部的。这只是hex包与binary包之间的功能职责边界的划分问题。

src := []byte("abc123") 

这里派生出了一个新的知识点,那就是编码格式:

src := []byte("abc123") 这个事件其实做了两件事:

1.将string类型的字符串转化成了AScii或utf-8编码

2.将这个编码转化成机器可以识别的二进制大端字节序

https://www.cnblogs.com/dzhy/p/10936926.html

如下文章虽然没具体针对性的描述,但是也可以说明,"字符"与"字节"之间是真实存在一个转换环节的

这也是一种协议,而协议的名称就是一直以来的ASCII、GB2312、UTF-8等

func main() {
    str := "test笃志弘毅"
    for i := 0; i < len(str); i++ {
        fmt.Printf("%v %c,", str[i], str[i])
    }
}
//116 t,101 e,115 s,116 t,231 ç,172 ¬,131 �,229 å,191 ¿,151 �,229 å,188 ¼,152 �,230 æ,175 ¯,133 �

而文章中如上内容所示,不用看别的,只需要看t打印出了116,就可以说明golang至少是进行了ASCII的隐式转换

而转换的触发位置就是在“str := "test笃志弘毅"”这里实现的,将"test笃志弘毅"写入内存时,采用了ASCII或UTF-8的协议模式储存与单独的各个临时的容器内,这就是第一步

而第二步所进行的,才是将临时容器内所代表的内容转换为二进制大端序,从而真正储存于计算机中

回到主题,如果将一个raw转化为一个整形(int)是并不会设计上面的“字节与字符”之间的协议转换的,明白这点是想明白16进制数相关操作的基础

继续分析如下文章:

https://blog.csdn.net/itpika/article/details/94594795

dst := make([]byte,hex.EncodedLen(len(src))) 这句话其实可以理解为

先计算出src这个字符串需要多少个8位二进制来储存

也就等同于知道了要多少个二进制数来储存了(8*len(src))

之后可能是会除8吧,因为2*8=16,就可以计算出需要多少个16进制数来储存了,从而设定好了储存容器的大小

之后的下一步:hex.Encode(dst,src)直接进行纯粹的转化操作或者说是,将一个utf8或ascii的编码内容转化为纯粹的16进制数,在将这个16进制数按照二进制大端字节序村道一个设定好大小的[]byte里

hex包所进行的操作,其实等同于字符串与utf8或ascii之间的过渡关系,或者说是,这个包经常会负责ascii与hex之间的相互转化关系

但也不是唯一的功能价值,其核心还是围绕着16进制的“协议”,也就是逢16进1,可以将一个raw转化成一个16进制整形的“临时状态”,而转换的前提是要基于那个无形的raw来操作,而不能直接通过string、int等“临时”类型,对于golang来说,唯一可以作为他的参数表进行操作的raw,只有byte切片这种形式

将一个string类型[]byte(str)后,在用二进制大端序给人类表达出来,就已经是个全新的内容了,不用再去顾虑string最初是什么,而这个全新的内容由于遵循二进制大端序协议,所以可以根据16进制完美协议转化一个16进制数,而这个数也是全新的

Clone this wiki locally