golang 宝藏库推荐 - Go语言中文社区

golang 宝藏库推荐


1. 写在最前面

笔者在去年 coding 的时候,有用到两个比较好用的库,在此记录下,以便后面再次使用,同时也方便那些有这方面需求的参考。

  • golang map to structure 的库 — https://github.com/mitchellh/mapstructure

  • golang json 校验库 — https://github.com/go-playground/validator

2. mapstructure

2.1 用途

将通用 map[string]interface{}解码到对应的 Go 结构体中。

注:Restful api body 解析时,一般先使用标准的 encoding/json 库将数据解码为 map[string]interface{}类型,然后使用 mapstructure 库将其转换为 Go 结构体中。

​ 上述多一次转换的好处是,当 api body 定义不兼容时,相比于直接定义 body 结构,此种方式不会影响原有的解析结构。

2.2 例子

详细介绍这个库的使用的文章,google 上很多,此处不做赘述,仅说一下此处使用的点。

package main

import (
	"fmt"

	"github.com/mitchellh/mapstructure"
)

type School struct {
	name string
}

type Person struct {
	Name    string
	Address string
	Phones  []string
	XInfo   string `json:"x-info"`
	School  School
}

func DecodesExample() {
	m := map[string]interface{}{
		"name":    "xiyan",
		"address": "earth",
		"x-info":  "not-parse",
		"phones":  []string{"12345678", "87654321"}, // object type
		"school":  School{name: "xy"},               // nested structure
	}
	var p Person
	err := mapstructure.Decode(m, &p)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%#v", p)
}

func main() {
	DecodesExample()
}

输出:

 mapToStruct $>go run main.go
main.Person{Name:"xiyan", Address:"earth", Phones:[]string{"12345678", "87654321"}, XInfo:"", School:main.School{name:"xy"}}

2.3 坑说明

2.2 中的例子,展示了如何将一个 map[stirng]interface{} 的结构,转换为自定义的 go 结构。

  • map 可以包含 slice 等 object 类型

  • map 可以包含自定义的 structue 类型

  • map 中包含的 key 如果包含 - 中划线则该字段不会被解析成功,但包含 ‘_’ 可以

    注:参见 “x-info”: “not-parse” ,笔者暂时未找到原因,猜测跟 go 变量命名包含字母、数字、下划线有关系。

3. validator

3.1 用途

在 web 应用中经常会遇到数据验证问题,比较常用的的是包 validator。其原理是将验证规则写在 struct 对应字段 tag 里,然后再通过反射获取 struct 的 tag,实现数据验证。

3.2 例子

package main

import (
	"fmt"

	"github.com/go-playground/validator/v10"
)

func BasicExample() {
	type Person struct {
		Name string `json:"name" validate:"required"`
		Age  int64  `json:"age" validate:"required"`
	}
	p := Person{
		Name: "",
		Age:  18,
	}
	v := validator.New()
	err := v.Struct(p)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(p)
}

func FieldExample() {
	type Person struct {
		// 注意:required与nameValidator 之间只能有 「,」 不能有空格
		Name string `json:"name" validate:"required,nameValidator"`
		Age  int64  `json:"age" validate:"required"`
	}

	nameValidator := func(f validator.FieldLevel) bool {
		return f.Field().String() != "xiyan"
	}

	v := validator.New()
	v.RegisterValidation("nameValidator", nameValidator)

	p := Person{
		Name: "xiyan",
		Age:  19,
	}
	err := v.Struct(p)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(p)
}

func SturctLevelExample() {
	type Person struct {
		Name string `json:"name" validate:"required"`
		Age  int64  `json:"age" validate:"required"`
	}

	structValidator := func(f validator.StructLevel) {
		p := f.Current().Interface().(Person)
		if p.Name == "xiyan" {
			f.ReportError(p.Name, "Name", "name", "name", "")

		}
		if p.Age > 80 {
			f.ReportError(p.Age, "Age", "age", "age", "")

		}
	}

	v := validator.New()
	v.RegisterStructValidation(structValidator, Person{})

	p := Person{
		Name: "xiyan",
		Age:  81,
	}
	err := v.Struct(p)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(p)
}

func main() {
	// FieldExample()
	SturctLevelExample()
}

上述的例子包括三部分:

  • 直接在 sturcture 定义的 tag 部分定义校验规则 — BasicExample
  • 针对 structure 的 Field 字段定义特定函数做校验 — FieldExample
  • 针对 structure 的整体做特定函数的校验 — SturctLevelExample

此处笔者使用的是 SturctLevelExample 的校验方式,遇到的问题是,识别出来的具体错误没有办法抛出到上层,上层只能查看到指定字段的错误,具体值错在哪里无法识别。

注:办法总比问题多,这里在暴露错误的使用上,笔者用了个 dirty 的处理方法,将错误的字段通过 tag 字段暴露,然后再从上层的 error 字段将 Tag 取出。

3.3 坑说明

具体例子

func SturctLevelExample() {
	type Person struct {
		Name string `json:"name" validate:"required"`
		Age  int64  `json:"age" validate:"required"`
	}

	structValidator := func(f validator.StructLevel) {
		p := f.Current().Interface().(Person)
		if p.Name == "xiyan" {
			f.ReportError(p.Name, "Name", "name", "name should not equal xiyan", "")

		}
		if p.Age > 80 {
			f.ReportError(p.Age, "Age", "age", "age should not greater than 80", "")

		}
	}

	v := validator.New()
	v.RegisterStructValidation(structValidator, Person{})

	p := Person{
		Name: "xiyan",
		Age:  81,
	}
	err := v.Struct(p)
	if err != nil {
		for _, e := range err.(validator.ValidationErrors) {
			fmt.Println(e.Tag())
		}
		return
	}
	fmt.Println(p)
}

func main() {
	SturctLevelExample()
}

输出:

validator $> go run main.go
name should not equal xiyan
age should not greater than 80

4. 碎碎念

今天是个好日子,希望加班的人都能早点下班哦。

  • 希望你可以明白,长大对你而言,是可以做更多想做的事,而不是被迫做更多不想做的事。
  • 我希望你可以活得开心,做你喜欢做的事,累的时候喝酒吹吹风,过你想要的生活。
  • 喜欢就争取,得到就珍惜,错过就忘记。

人生快乐法则之一,就是吃东西的时候就考虑东西好不好吃。

5. 参考资料

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/phantom_111/article/details/122929896
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2023-01-03 20:59:07
  • 阅读 ( 478 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢