Go 语言中的动态 JSON

Python010

Go 语言中的动态 JSON,第1张

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

前面,我们讲了map的用法以及原理 Golang中map的实现原理 ,但我们知道,map在并发读写的情况下是不安全。需要并发读写时,一般的做法是加锁,但这样性能并不高,Go语言在 1.9 版本中提供了一种效率较高的并发安全的 sync.Map,今天,我们就来讲讲 sync.Map的用法以及原理

sync.Map与map不同,不是以语言原生形态提供,而是在 sync 包下的特殊结构:

我们下来看下sync.Map结构体

结构体之间的关系如下图所示:

总结一下:

Load方法比较简单,总结一下:

总结如下:

Map是java中的接口,Map.Entry是Map的一个内部接口。

Map提供了一些常用方法,如keySet()、entrySet()等方法,keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。

Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。

由以上可以得出,遍历Map的常用方法:

1.

Map map = new HashMap()

           Irerator iterator = map.entrySet().iterator()

           while(iterator.hasNext()) {

                   Map.Entry entry = iterator.next()

                   Object key = entry.getKey()

                   //

           }

2.

Map map = new HashMap() 

           Set  keySet= map.keySet()

           Irerator iterator = keySet.iterator

           while(iterator.hasNext()) {

                   Object key = iterator.next()

                   Object value = map.get(key)

                   //

           }

另外,还有一种遍历方法是,单纯的遍历value值,Map有一个values方法,返回的是value的Collection集合。通过遍历collection也可以遍历value,如

     Map map = new HashMap()

      Collection c = map.values()

      Iterator iterator = c.iterator()

      while(iterator.hasNext()) {

             Object value = iterator.next() 

     }

/*---------------------------详解2----------------------------------*/

你是否已经对每次从Map中取得关键字然后再取得相应的值感觉厌倦?使用Map.Entry类,你可以得到在同一时间得到所有的信息。标准的Map访问方法如下:

Set keys = map.keySet( )

if(keys != null) {

Iterator iterator = keys.iterator( )

while(iterator.hasNext( )) {

Object key = iterator.next( )

Object value = map.get(key)

....

}

}

然后,这个方法有一个问题。从Map中取得关键字之后,我们必须每次重复返回到Map中取得相对的值,这是很繁琐和费时的。

幸运的是,这里有一个更加简单的途径。Map类提供了一个称为entrySet()的方法,这个方法返回一个Map.Entry实例化后的对象集。 接着,Map.Entry类提供了一个getKey()方法和一个getValue()方法,因此,上面的代码可以被组织得更符合逻辑。举例如下:

Set entries = map.entrySet( )

if(entries != null) {

Iterator iterator = entries.iterator( )

while(iterator.hasNext( )) {

Map.Entry entry =iterator.next( )

Object key = entry.getKey( )

Object value = entry.getValue()

....

}

}

尽管增加了一行代码,我们却省略了许多对Map不必要的“get”调用。同时,提供给开发人员一个同时保持了关键字和其对应的值的类。Map.Entry同时也提供了一个setValue()方法,程序员可以使用它修改map里面的值。