go语言中 go语言中文文档( 二 )


Go 语言中的动态 JSON Go 语言是静态类型语言,虽然它也可以表现出动态类型,但是使用一个嵌套的 map[string]interface{} 在那里乱叫会让代码变得特别丑 。通过掌握语言的静态特性 , 我们可以做的更好 。
通过同一通道交换多种信息的时候,我们经常需要 JSON 具有动态的,或者更合适的参数内容 。首先,让我们来讨论一下消息封装(message envelopes),JSON 在这里看起来就像这样:
通过 interface{},我们可以很容易的将数据结构编码成为独立封装的,具有多种类型的消息体的 JSON 数据 。为了生成下面的 JSON :
我们可以使用这些 Go 类型:
输出的结果是:
这些并没有什么特殊的 。
如果你想将上面的 JSON 对象解析成为一个 Envelope 类型的对象,最终你会将 Msg 字段解析成为一个 map[string]interface{} 。这种方式不是很好用,会使你后悔你的选择 。
输出:
就像前面说的,我推荐修改 Envelope 类型,就像这样:
json.RawMessage非常有用,它可以让你延迟解析相应的 JSON 数据 。它会将未处理的数据存储为 []byte 。
这种方式可以让你显式控制 Msg 的解析 。从而延迟到获取到 Type 的值之后,依据 Type 的值进行解析 。这种方式不好的地方在于你需要先明确解析 Msg,或者你需要单独分为 EnvelopeIn 和 EnvelopeOut 两种类型,其中 EnvelopeOut 仍然有 Msg interface{} 。
那么如何将上述两者好的一面结合起来呢?通过在 interface{} 字段中放入 *json.RawMessage!
输出:
虽然我极其推荐你将动态可变的部分放在一个单独的 key 下面 , 但是有时你可能需要处理一些预先存在的数据,它们并没有用这样的方式进行格式化 。
如果可以的话,请使用文章前面提到的风格 。
我们可以通过解析两次数据的方式来解决 。
dynamite
Go语言中的结构体作为C语言家族的一员,go和c一样也支持结构体 。可以类比于java的一个POJO 。
在学习定义结构体之前,先学习下定义一个新类型 。
新类型 T1 是基于 Go 原生类型 int 定义的新自定义类型,而新类型 T2 则是 基于刚刚定义的类型 T1,定义的新类型 。
这里要引入一个底层类型的概念 。
如果一个新类型是基于某个 Go 原生类型定义的,那么我们就叫 Go 原生类型为新类型的底层类型
在上面的例子中,int就是T1的底层类型 。
但是T1不是T2的底层类型,只有原生类型才可以作为底层类型 , 所以T2的底层类型还是int
底层类型是很重要的,因为对两个变量进行显式的类型转换,只有底层类型相同的变量间才能相互转换 。底层类型是判断两个类型本质上是否相同的根本 。
这种类型定义方式通常用在 项目的渐进式重构,还有对已有包的二次封装方面
类型别名表示新类型和原类型完全等价,实际上就是同一种类型 。只不过名字不同而已 。
一般我们都是定义一个有名的结构体 。
字段名的大小写决定了字段是否包外可用 。只有大写的字段可以被包外引用 。
还有一个点提一下
如果换行来写
Age: 66,后面这个都好不能省略
还有一个点,观察e3的赋值
new返回的是一个指针 。然后指针可以直接点号赋值 。这说明go默认进行了取值操作
e3.Age等价于(*e3).Age
如上定义了一个空的结构体Empty 。打印了元素e的内存大小是0 。
有什么用呢?
基于空结构体类型内存零开销这样的特性,我们在日常 Go 开发中会经常使用空 结构体类型元素,作为一种“事件”信息进行 Goroutine 之间的通信

推荐阅读