21 JSON and Go go语言和json
JSON and Go
25 January 2011
Introduction
JSON (JavaScript Object Notation) is a simple data interchange format. Syntactically it resembles the objects and lists of JavaScript. It is most commonly used for communication between web back-ends and JavaScript programs running in the browser, but it is used in many other places, too. Its home page, json.org, provides a wonderfully clear and concise definition of the standard.
With the json package it's a snap to read and write JSON data from your Go programs.
Encoding
To encode JSON data we use the Marshal function.
func Marshal(v interface{}) ([]byte, error)
Given the Go data structure, Message,
type Message struct {
Name string
Body string
Time int64
}
and an instance of Message
m := Message{"Alice", "Hello", 1294706395881547000}
we can marshal a JSON-encoded version of m using json.Marshal:
b, err := json.Marshal(m)
If all is well, err will be nil and b will be a []byte containing this JSON data:
b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
Only data structures that can be represented as valid JSON will be encoded:
- JSON objects only support strings as keys; to encode a Go map type it must be of the form
map[string]T(whereTis any Go type supported by the json package).
- Channel, complex, and function types cannot be encoded.
- Cyclic data structures are not supported; they will cause
Marshalto go into an infinite loop.
- Pointers will be encoded as the values they point to (or 'null' if the pointer is
nil).
The json package only accesses the exported fields of struct types (those that begin with an uppercase letter). Therefore only the the exported fields of a struct will be present in the JSON output.
Decoding
To decode JSON data we use the Unmarshal function.
func Unmarshal(data []byte, v interface{}) error
We must first create a place where the decoded data will be stored
var m Message
and call json.Unmarshal, passing it a []byte of JSON data and a pointer to m
err := json.Unmarshal(b, &m)
If b contains valid JSON that fits in m, after the call err will be nil and the data from b will have been stored in the struct m, as if by an assignment like:
m = Message{
Name: "Alice",
Body: "Hello",
Time: 1294706395881547000,
}
How does Unmarshal identify the fields in which to store the decoded data? For a given JSON key "Foo", Unmarshal will look through the destination struct's fields to find (in order of preference):
- An exported field with a tag of
"Foo"(see the Go spec for more on struct tags),
- An exported field named
"Foo", or
- An exported field named
"FOO"or"FoO"or some other case-insensitive match of"Foo".
What happens when the structure of the JSON data doesn't exactly match the Go type?
b := []byte(`{"Name":"Bob","Food":"Pickle"}`)
var m Message
err := json.Unmarshal(b, &m)
Unmarshal will decode only the fields that it can find in the destination type. In this case, only the Name field of m will be populated, and the Food field will be ignored. This behavior is particularly useful when you wish to pick only a few specific fields out of a large JSON blob. It also means that any unexported fields in the destination struct will be unaffected by Unmarshal.
But what if you don't know the structure of your JSON data beforehand?
Generic JSON with interface{}
The interface{} (empty interface) type describes an interface with zero methods. Every Go type implements at least zero methods and therefore satisfies the empty interface.
The empty interface serves as a general container type:
var i interface{}
i = "a string"
i = 2011
i = 2.777
A type assertion accesses the underlying concrete type:
r := i.(float64)
fmt.Println("the circle's area", math.Pi*r*r)
Or, if the underlying type is unknown, a type switch determines the type:
switch v := i.(type) {
case int:
fmt.Println("twice i is", v*2)
case float64:
fmt.Println("the reciprocal of i is", 1/v)
case string:
h := len(v) / 2
fmt.Println("i swapped by halves is", v[h:]+v[:h])
default:
// i isn't one of the types above
}
The json package uses map[string]interface{} and []interface{} values to store arbitrary JSON objects and arrays; it will happily unmarshal any valid JSON blob into a plain interface{} value. The default concrete Go types are:
boolfor JSON booleans,
float64for JSON numbers,
stringfor JSON strings, and
nilfor JSON null.
Decoding arbitrary data
Consider this JSON data, stored in the variable b:
b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
Without knowing this data's structure, we can decode it into an interface{} value with Unmarshal:
var f interface{}
err := json.Unmarshal(b, &f)
At this point the Go value in f would be a map whose keys are strings and whose values are themselves stored as empty interface values:
f = map[string]interface{}{
"Name": "Wednesday",
"Age": 6,
"Parents": []interface{}{
"Gomez",
"Morticia",
},
}
To access this data we can use a type assertion to access f's underlying map[string]interface{}:
m := f.(map[string]interface{})
We can then iterate through the map with a range statement and use a type switch to access its values as their concrete types:
for k, v := range m {
switch vv := v.(type) {
case string:
fmt.Println(k, "is string", vv)
case float64:
fmt.Println(k, "is float64", vv)
case []interface{}:
fmt.Println(k, "is an array:")
for i, u := range vv {
fmt.Println(i, u)
}
default:
fmt.Println(k, "is of a type I don't know how to handle")
}
}
In this way you can work with unknown JSON data while still enjoying the benefits of type safety.
Reference Types
Let's define a Go type to contain the data from the previous example:
type FamilyMember struct {
Name string
Age int
Parents []string
}
var m FamilyMember
err := json.Unmarshal(b, &m)
Unmarshaling that data into a FamilyMember value works as expected, but if we look closely we can see a remarkable thing has happened. With the var statement we allocated a FamilyMember struct, and then provided a pointer to that value to Unmarshal, but at that time the Parents field was a nil slice value. To populate the Parents field, Unmarshal allocated a new slice behind the scenes. This is typical of how Unmarshal works with the supported reference types (pointers, slices, and maps).
Consider unmarshaling into this data structure:
type Foo struct {
Bar *Bar
}
If there were a Bar field in the JSON object, Unmarshal would allocate a new Bar and populate it. If not, Barwould be left as a nil pointer.
From this a useful pattern arises: if you have an application that receives a few distinct message types, you might define "receiver" structure like
type IncomingMessage struct {
Cmd *Command
Msg *Message
}
and the sending party can populate the Cmd field and/or the Msg field of the top-level JSON object, depending on the type of message they want to communicate. Unmarshal, when decoding the JSON into an IncomingMessagestruct, will only allocate the data structures present in the JSON data. To know which messages to process, the programmer need simply test that either Cmd or Msg is not nil.
Streaming Encoders and Decoders
The json package provides Decoder and Encoder types to support the common operation of reading and writing streams of JSON data. The NewDecoder and NewEncoder functions wrap the io.Reader and io.Writer interface types.
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder
Here's an example program that reads a series of JSON objects from standard input, removes all but the Namefield from each object, and then writes the objects to standard output:
package main import (
"encoding/json"
"log"
"os"
) func main() {
dec := json.NewDecoder(os.Stdin)
enc := json.NewEncoder(os.Stdout)
for {
var v map[string]interface{}
if err := dec.Decode(&v); err != nil {
log.Println(err)
return
}
for k := range v {
if k != "Name" {
delete(v, k)
}
}
if err := enc.Encode(&v); err != nil {
log.Println(err)
}
}
}
Due to the ubiquity of Readers and Writers, these Encoder and Decoder types can be used in a broad range of scenarios, such as reading and writing to HTTP connections, WebSockets, or files.
References
For more information see the json package documentation. For an example usage of json see the source files of the jsonrpc package.
By Andrew Gerrand
Related articles
- HTTP/2 Server Push
- Introducing HTTP Tracing
- Generating code
- Introducing the Go Race Detector
- Go maps in action
- go fmt your code
- Organizing Go code
- Debugging Go programs with the GNU Debugger
- The Go image/draw package
- The Go image package
- The Laws of Reflection
- Error handling and Go
- "First Class Functions in Go"
- Profiling Go Programs
- A GIF decoder: an exercise in Go interfaces
- Introducing Gofix
- Godoc: documenting Go code
- Gobs of data
- C? Go? Cgo!
- Go Slices: usage and internals
- Go Concurrency Patterns: Timing out, moving on
- Defer, Panic, and Recover
- Share Memory By Communicating
- JSON-RPC: a tale of interfaces
21 JSON and Go go语言和json的更多相关文章
- 【java/Json】用Java对象构建Json语法树
本文后续:https://www.cnblogs.com/xiandedanteng/p/11973129.html 编译第一步:将文本解析成Java对象构成的语法树 第二步:将语法树输出整形好的Js ...
- 【翻译】Scriban README 文本模板语言和.NET引擎
scriban Scriban是一种快速.强大.安全和轻量级的文本模板语言和.NET引擎,具有解析liquid模板的兼容模式 Github https://github.com/lunet-io/sc ...
- MVC中Json的使用:Controller中Json的处理
一.当查询得到的数据符合前台要求,不需要做任何处理,直接DataList To Json 返回前台. 代码: , out recordCount); return Json(allEntities, ...
- json学习系列(8)JSON与JAVA数据的相互转换实例
一.完整案例 先定义一个java实体对象,如下: package com.pcitc.json.cnblog; /** * SimInfo实体对象 * * @Description * @author ...
- MVC中Json的使用:Controller中Json的处理【转】
一.当查询得到的数据符合前台要求,不需要做任何处理,直接DataList To Json 返回前台. 代码: , out recordCount); return Json(allEntities, ...
- json进阶(一)js读取解析JSON类型数据
js读取解析JSON类型数据 一.什么是JSON? JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,是理想的数据交换格式,同 ...
- 聊聊C语言和ABAP
这个公众号之前的文章,分享的都是Jerry和SAP成都研究院的同事在工作中学到的一些知识和感受.而今天这篇文章,写作的由来是因为最近我又参与了SAP成都数字创新空间应聘者的面试,和一些朋友聊了一些关于 ...
- 浅谈JSON与与JS相关的JSON函数
本文内容主要引用在微信公众号上看到的一片文章,因为自己对Json了解不是很深入,所以就整理出这篇博文与大家分享! 一. JSON是一种格式,基于文本,优于轻量,用于交换数据 1.一种数据格式 数据的传 ...
- JSON对象和字符串之间的相互转换 – JSON.parse() 和 JSON.stringify()
所有现代浏览器都支持 JSON 对象,有两个非常有用的方法来处理 JSON 格式的内容: JSON.parse(string) :接受一个 JSON 字符串并将其转换成一个 JavaScript 对象 ...
随机推荐
- Fork/Join框架实现原理
ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责存放程序提交给ForkJoinPool的任务,而ForkJoi ...
- Java之高级IO,Properties
IO流(高级) 释放资源的标准代码 主要考虑的是在什么时候释放资源比较合适.而且在jdk1.7之前和之后是不同的. package com.wzlove.demo; import java.io.Fi ...
- idea中复制module和module中的蓝色tag出现的方法
1.在从github上面导入项目到idea中时,经常好多module都是没有蓝色的tag的,这说明这不是个maven形式的module,需要导入到项目中. 举个例子: 有蓝色tag的module才可以 ...
- 01 C++ 多线程入门实例
1.可复用的完整实例 #include <iostream> #include <thread> #include <mutex> using namespace ...
- 二、Linux学习之centOS的的setup
因为我是在VMware上安装的centOS,网络设置选择的是桥接模式,这样可以和实体机使用同样的网络,但是也使用同样的IP,因此就需要设置一下IP了,否则使用ifconfig查询ip的时候显示的是12 ...
- .gitignore 无效问题
利用.gitignore过滤文件,如编译过程中的中间文件,等等,这些文件不需要被追踪管理. 现象: 在.gitignore添加file1文件,以过滤该文件,但是通过Git status查看仍显示fil ...
- 字典的setdefault() 和get()方法比较
Python 字典 setdefault() 函数 和get() 类似: 如果键存在字典中,返回其value值 如果键不存在字典中,创建键值对.完后,返回值为默认值. 话不多说,上栗子: setdef ...
- Ubuntu 搭建svn服务器 ,以及常见错误解决方案
一.安装命令: 1)以root身份登录.执行:sudo su -命令 2)执行安装命令:apt-get install subversion 二.创建项目目录 1)mkdir /home/svn ...
- Http 学习笔记(一)
介绍 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议.. ...
- shell逐行读取excel并执行sql
背景:测试同学想根据一组user_id 获取token做测试,由于各种原因(数据量大,sql语句复杂),只能根据user_id一条条查,于是写了个脚本: 1, 先查询需要的user_id 导出到use ...