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
(whereT
is 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
Marshal
to 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:
bool
for JSON booleans,
float64
for JSON numbers,
string
for JSON strings, and
nil
for 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, Bar
would 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 IncomingMessage
struct, 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 Name
field 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 对象 ...
随机推荐
- Linux进程间通信(消息队列/信号量+共享内存)
写在前面 不得不说,Deadline果真是第一生产力.不过做出来的东西真的是不堪入目,于是又花了一早上重写代码. 实验内容 进程通信的邮箱方式由操作系统提供形如 send()和 receive()的系 ...
- BZOJ2142 礼物 【扩展Lucas】
题目 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多.小E从商店中购买了n件礼物, ...
- 【bzoj1483】 HNOI2009—梦幻布丁
http://www.lydsy.com/JudgeOnline/problem.php?id=1483 (题目链接) 题意 $n$个布丁摆成一行,进行$m$次操作.每次将某个颜色的布丁全部变成另一种 ...
- JS的作用域和闭包
1.作用域 作用域是根据名称找变量的一套规则. 变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在作用域中查找该变量,如果能够找到就会对它 ...
- Docker应用二:docker常用命令介绍
Docker常用命令使用介绍 docker中常用的命令: 1.docker search image_name:搜查镜像 2.docker pull image_name:从镜像库中拉去镜像 3.d ...
- Ubuntu 搭建svn服务器 ,以及常见错误解决方案
一.安装命令: 1)以root身份登录.执行:sudo su -命令 2)执行安装命令:apt-get install subversion 二.创建项目目录 1)mkdir /home/svn ...
- bzoj千题计划130:bzoj1305: [CQOI2009]dance跳舞
http://www.lydsy.com/JudgeOnline/problem.php?id=1305 每个人拆为喜欢(yes)和不喜欢(no)两个点 二分答案 1.每两个人之间只能跳一次 喜欢则 ...
- 51 nod 1105 第K大的数
1105 第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 数组A和数组B,里面都有n个整数.数组C共有n^2个整数,分别是A[0] * ...
- PHP7 学习笔记(一)Ubuntu 16.04 编译安装Nginx-1.10.3、 PHP7.0.9、Redis3.0 扩展、Phalcon3.1 扩展、Swoole1.9.8 扩展、ssh2扩展(全程编译安装)
==================== PHP 7.0 编译安装================== wget http://cn2.php.net/get/php-7.0.9.tar.bz2/fr ...
- [转载]Require.js Example – Setup Time 2 Minutes
http://www.sitepoint.com/require-js-setup-time-2-minutes/ Setup Require.js in just 2 minutes. or dow ...