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 对象 ...
随机推荐
- BZOJ 1283: 序列
1283: 序列 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 272 Solved: 151[Submit][Status][Discuss] D ...
- 【BZOJ3309】DZY Loves Math 解题报告
[BZOJ3309]DZY Loves Math Description 对于正整数\(n\),定义\(f(n)\)为\(n\)所含质因子的最大幂指数.例如\(f(1960)=f(2^3×5^1×7^ ...
- 【bzoj1483】 HNOI2009—梦幻布丁
http://www.lydsy.com/JudgeOnline/problem.php?id=1483 (题目链接) 题意 $n$个布丁摆成一行,进行$m$次操作.每次将某个颜色的布丁全部变成另一种 ...
- poj 2396 Budget
一个m行n列的矩阵,给出每行每列中元素的和,以及对一些格子的大小限制,求一个可行方案,输出矩阵. 大小限制形如:严格大于i,严格小于i,等于i. 1<=m<=200.1<=n< ...
- 【Asp.net入门06】第一个ASP.NET 应用程序-案例说明
创建简单的应用程序 本章的剩余部分将探讨一些用于创建简单的数据输入应用程序的基本ASP.NET功能.在这一节中,我们将加快进度——目标是演示ASP.NET的用法,因此将略过有关后台运行机制的详细说明. ...
- css table 合并单元格
1. css table 合并单元格 colspan:合并列, rowspan:合并行, 合并行的时候,比如rowspan="2",它的下一行tr会少一列: 合并列的时候,比如co ...
- Spark记录-Scala数据类型
Scala与Java具有相同的数据类型,具有相同的内存占用和精度.以下是提供Scala中可用的所有数据类型的详细信息的表格: 序号 数据类型 说明 1 Byte 8位有符号值,范围从-128至127 ...
- Java并发编程原理与实战三:多线程与多进程的联系以及上下文切换所导致资源浪费问题
一.进程 考虑一个场景:浏览器,网易云音乐以及notepad++ 三个软件只能顺序执行是怎样一种场景呢?另外,假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而 ...
- 学以致用:Python爬取廖大Python教程制作pdf
当我学了廖大的Python教程后,感觉总得做点什么,正好自己想随时查阅,于是就开始有了制作PDF这个想法. 想要把教程变成PDF有三步: 先生成空html,爬取每一篇教程放进一个新生成的div,这样就 ...
- AngularJS 、Backbone.js 和 Ember.js 的比较
1 介绍 我们准备在这篇文章中比较三款流行于Web的“模型-视图-*”框架:AngularJS.Backbone和Ember.为你的项目选择正确的框架能够对你及时交付项目的能力和在以后维护你自己代码的 ...