首页 > 其他分享 >Go 每日一库之 sjson(转)

Go 每日一库之 sjson(转)

时间:2022-08-22 00:13:57浏览次数:104  
标签:Println name sjson fmt 一库 fruits Go newValue

转自Go 每日一库之 sjson

简介

在上一篇文章中我们介绍了如何使用gjson快速读取 JSON 串中的值。为了内容的完整性,今天我们介绍一下如何使用sjson快速设置 JSON 串中的值。

快速使用

先安装:

$ go get github.com/tidwall/sjson

使用:

package main

import (
  "fmt"

  "github.com/tidwall/sjson"
)

const json = `{"name":{"first":"li","last":"dj"},"age":18}`

func main() {
  value, _ := sjson.Set(json, "name.last", "dajun")
  fmt.Println(value)
}

上面代码通过 sjson.Set() 将 JSON 串中name.last对应的值设置为dajun。与gjson一样,sjson也通过键路径指定具体的位置,键路径即为一系列以.分隔的键。sjson支持的键路径语法是gjson的一个子集,具体键路径的语法可以参见上一篇文章。sjson.Set()返回设置之后的 JSON 串。最终程序输出:

{"name":{"first":"li","last":"dajun"},"age":18}

支持的类型

sjson支持的类型包括nil/bool/int/float/string等。如果传入sjson不支持的类型,sjson会调用json.Marshal,然后将生成的字符串设置到对应的键路径上:

type User struct {
  Name string `json:"name"`
  Age  int    `json:"age"`
}

func main() {
  nilJSON, _ := sjson.Set("", "key", nil)
  fmt.Println(nilJSON)

  boolJSON, _ := sjson.Set("", "key", false)
  fmt.Println(boolJSON)

  intJSON, _ := sjson.Set("", "key", 1)
  fmt.Println(intJSON)

  floatJSON, _ := sjson.Set("", "key", 10.5)
  fmt.Println(floatJSON)

  strJSON, _ := sjson.Set("", "key", "hello")
  fmt.Println(strJSON)

  mapJSON, _ := sjson.Set("", "key", map[string]interface{}{"hello": "world"})
  fmt.Println(mapJSON)

  u := User{Name: "dj", Age: 18}
  structJSON, _ := sjson.Set("", "key", u)
  fmt.Println(structJSON)
}

注意,我们传入一个空字符串,sjson.Set()会生成一个空对象,然后按照键路径依次设置值。下面分析上述程序输出:

  • nil:在 JSON 中用null表示,输出{"key":null};

  • false:在 JSON 中布尔值用true/false表示,输出{"key":false};

  • 1和10.5:整数和浮点数在 JSON 中都用number表示,分别输出{"key":1}和{"key":10.5};

  • hello:输出{"key":"hello"};

  • map[string]interface{}:sjson并不原生支持map类型,故通过json.Marshal将其序列化为{"hello":"world"}再设置到键key上,输出{"key":{"hello":"world"}};

  • User对象:先通过json.Marshal序列化为{"name":"dj","age":18}再设置;

修改数组

修改数组可以通过在键路径后添加索引,有两种特殊情况:

  • 使用-1或数组长度为索引表示在数组后添加一个新元素;

  • 使用的索引超出数组的长度,会在数组中添加很多null值。

看下面示例:

func main() {

  fruits := `{"fruits":["apple", "orange", "banana"]}`

  var newValue string
  newValue, _ = sjson.Delete(fruits, "fruits.1")
  fmt.Println(newValue)

  newValue, _ = sjson.Delete(fruits, "fruits.-1")
  fmt.Println(newValue)

  newValue, _ = sjson.Set(fruits, "fruits.5")
  fmt.Println(newValue)
}

fruits.1:设置第二个水果为grape(索引从 0 开始),输出{"fruits":["apple", "grape", "banana"]};
fruits.3:由于数组长度为 3,使用 3 表示在数组后添加一个元素,输出{"fruits":["apple","orange","banana","pear"]};
fruits.-1:使用-1同样表示在数组后添加一个元素,输出{"fruits":["apple", "orange", "banana","strawberry"]};
fruits.5:索引 5 已经大于数组长度 3 了,所以会多出两个null,输出{"fruits":["apple","orange","banana",null,null,"watermelon"]}。

删除

删除数组元素需要调用sjson.Delete()方法,键路径语法相同。如果键路径对应的值不存在,则Delete()无效果:

func main() {
  var newValue string
  user := `{"name":{"first":"li","last":"dj"},"age":18}`

  newValue, _ = sjson.Delete(user, "name.first")
  fmt.Println(newValue)

  newValue, _ = sjson.Delete(user, "name.full")
  fmt.Println(newValue)

  fruits := `{"fruits":["apple", "orange", "banana"]}`

  newValue, _ = sjson.Delete(fruits, "fruits.1")
  fmt.Println(newValue)

  newValue, _ = sjson.Delete(fruits, "fruits.-1")
  fmt.Println(newValue)

  newValue, _ = sjson.Delete(fruits, "fruits.5")
  fmt.Println(newValue)
}

name.first:删除字段name.first,输出{"name":{"last":"dj"},"age":18};
name.full:由于字段name.full不存在,无效果,输出{"name":{"first":"li","last":"dj"},"age":18};
fruits.1:删除数组fruits的第二个元素,输出{"fruits":["apple", "banana"]};
fruits.-1:删除数组最后一个元素,输出{"fruits":["apple", "orange"]};
fruits.5:索引 5 超出数组长度 3,无效果,输出{"fruits":["apple", "orange", "banana"]}。

错误处理

使用sjson出现的错误分为两种,一种是传入的 JSON 串不是合法的串,另一种是键路径语法错误。Set()和Delete()方法返回的第二个参数为错误,只有非法的键路径会返回错误,非法 JSON 串不会。

非法 JSON 串

同gjson一样,sjson同样不会检查传入的 JSON 串的合法性,它假设传入的是合法的串。如果传入一个非法的 JSON 串,程序输出不确定的结果:

func main() {
  user := `{"name":dj,age:18}`
  newValue, err := sjson.Set(user, "name", "dajun")
  fmt.Println(err, newValue)
}

上面程序中,我故意传入一个非法的 JSON 串(dj和age漏掉了双引号)。最终程序输出:

<nil> {"name":dj,age:"dajun"}

将age变为了dajun,显然不正确。然而此时返回的err = nil。

非法键路径

与gjson相比,sjson能使用的键路径语法比较有限,不能使用通配符和一些条件语法。如果传入的键路径非法,将返回非空的错误值:

func main() {
  user := `{"name":"dj","age":18}`
  newValue, err := sjson.Set(user, "na?e", "dajun")
  fmt.Println(err, newValue)
}

上次使用通配符?,输出:

wildcard characters not allowed in path

总结

sjson比较简单易用,性能不俗。我们在确定 JSON 串合法的情况下,可使用它快速设置值。

大家如果发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue?

参考

sjson GitHub:https://github.com/tidwall/sjson
Go 每日一库 GitHub:https://github.com/darjun/go-daily-lib

转自Go 每日一库之 sjson

标签:Println,name,sjson,fmt,一库,fruits,Go,newValue
From: https://www.cnblogs.com/hi3254014978/p/16611487.html

相关文章

  • golang 查询 ES 最简单的 demo
    分页多条件查询ESfuncTestESQueryDemo(){//ESSDK教程:https://www.yisu.com/zixun/694102.html query:=elastic.NewBoolQuery().Must......
  • go 语言 channel for select
    示例demo55packagemainimport("fmt""time")funcmain(){intChan:=make(chanint,10)//初始化intchan通道长度10int......
  • go 语言 goroutine通信
    示例demo52packagemainimport("fmt")funccalc(taskChanchanint,resChanchanint,exitChanchanbool){forv:=rangetaskChan{......
  • golang语法速记
    Golang语言中存在一个关键字type,type又有两种使用方式,一种是类型别名,一种是类型定义。GoLang1.9后对內建定义类型使用了新的写法:typeNewName=Type这个NewName只是Typ......
  • Golang基础入门
    基础入门1、输出输出,在运行代码时将内容在终端输出。packagemainimport"fmt"funcmain(){fmt.Println("helloword!")}在Go中提供了多种输出的方式......
  • Django 2.0 新特点
    2017年12月2日,Django官方发布了2.0版本,成为多年来的第一次大版本提升,那么2.0对广大Django使用者有哪些变化和需要注意的地方呢?一、Python兼容性Django2.0支持Python3.......
  • Golang的IDE的安装
    Golang的IDE的安装Goland是一款由JetBrains公司开发的软件,使用他可以大大提高程序员开发Go代码的效率,因为Goland内部提供了编辑器、调试器和图形用户界面等很多方便的功......
  • golang反射reflect
    1reflect包reflect包实现了运行时反射,允许程序操作任意类型的对象。典型用法是用静态类型interface{}保存一个值,通过调用TypeOf获取其动态类型信息,该函数返回一个Type类......
  • PicGo+GitHub 图床搭建
    前言用GitHub搭建图床,在很久之前我就有了解,但由于市面上有挺多免费的图床,比如我之前一直在用的路过图床,所以一直懒得动手搭建GitHub图床。一直到前两天我在完善博客的相......
  • go 语言 chan读写数据
    示例demo51packagemainimport("fmt""time")funcsendData(chchanint){//把数据写到通道里fori:=0;i<20;i++{......