Golang JSON变量不加Tag 反射获取Tag

本文详细介绍了如何在Go语言中使用Unmarshal函数解析JSON数据,包括解析规则、数据类型匹配及特殊场景处理等核心内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JSON 解析

Unmarshal 解析 JSON 编码的数据,并将结果存入 v 指向的值。如果 v 为 nil 或不是指针,则 Unmarshal 返回 InvalidUnmarshalError。

Unmarshal 和 Marshal 做相反的操作,必要时申请 map、slice 或指针,有如下的附加规则:

  • 为了将 JSON 数据解码写入一个指针,Unmarshal 首先处理 JSON 数据为 JSON 字面值 null 的情况。此时,Unmarshal 会将指针设置为 nil。否则,Unmarshal 会将 JSON 数据解码为指针所指向的值。如果指针为 nil,则 Unmarshal 为其分配一个新值并使指针指向它。

  • 为了将 JSON 数据解码为实现 Unmarshaler 接口的值,Unmarshal 调用该值的 UnmarshalJSON 方法,包括当输入为 JSON null 时。否则,如果该值实现 encoding.TextUnmarshaler 且输入是带引号的 JSON 字符串,则 Unmarshal 会使用该字符串的未加引号形式来调用该值的 UnmarshalText 方法。

  • 要将 json 数据解码写入一个结构体,函数会匹配输入对象的键和 Marshal 使用的键(结构体字段名或者它的标签指定的键名),优先选择精确的匹配,但也接受大小写不敏感的匹配;

  • 为了将 JSON 数据解码到结构中,Unmarshal 将传入的对象键与 Marshal 使用的键(结构字段名称或其 Tag)进行匹配,希望使用精确匹配,但还接受不区分大小写的匹配。默认情况下,没有相应结构字段的对象键将被忽略(有关替代方法,请参见 Decoder.DisallowUnknownFields)。

  • 要将 JSON 数据解码写入一个接口类型值,Unmarshal 将其中之一存储在接口值中:

    Bool                   对应JSON布尔类型
    float64                对应JSON数字类型
    string                 对应JSON字符串类型
    []interface{}          对应JSON数组
    map[string]interface{} 对应JSON对象
    nil                    对应JSON的null
    
  • 要将一个 JSON 数组解码到切片(slice)中,Unmarshal 将切片长度重置为零,然后将每个元素 append 到切片中。特殊情况,如果将一个空的 JSON 数组解码到一个切片中,Unmarshal 会用一个新的空切片替换该切片。

  • 为了将 JSON 数组解码为 Go 数组,Unmarshal 将 JSON 数组元素解码为对应的 Go 数组元素。如果 Go 数组长度小于 JSON 数组,则其他 JSON 数组元素将被丢弃。如果 JSON 数组长度小于 Go 数组,则将其他 Go 数组元素会设置为零值。

  • 要将 JSON 对象解码到 map 中,Unmarshal 首先要建立将使用的 map。如果 map 为零,Unmarshal 会分配一个新 map。否则,Unmarshal 会重用现有 map,保留现有条目(item)。然后,Unmarshal 将来自 JSON 对象的键/值对存储到 map 中。map 的键类型必须是任意字符串类型、整数或实现了 json.Unmarshaler 或 encoding.TextUnmarshaler 接口的类型。

  • 如果 JSON 值不适用于给定的目标类型,或者 JSON 数字写入目标类型时溢出,则 Unmarshal 会跳过该字段并尽最大可能完成解析。如果没有遇到更多的严重错误,则 Unmarshal 返回一个 UnmarshalTypeError 来描述最早的此类错误。但无法确保有问题的字段之后的所有其余字段都将被解析到目标对象中。

  • JSON 的 null 值解码为 Go 的接口、指针、切片时会将它们设为 nil,因为 null 在 JSON 里一般表示“不存在”。 因此将 JSON null 解码到任何其他 Go 类型中不会影响该值,并且不会产生任何错误。

  • 解析带引号的字符串时,无效的 UTF-8 或无效的 UTF-16 不会被视为错误。而是将它们替换为 Unicode 字符 U+FFFD。

JSON包变量不加 Tag

type J struct {
	a string //小写无tag
	b string `json:"B"` //小写+tag
	C string //大写无tag
	D string `json:"DD" otherTag:"good"` //大写+tag
}

func printTag(stru interface{}) { //printTag方法传入的是j的指针。
	t := reflect.TypeOf(stru).Elem()    //reflect.TypeOf(stru).Elem()获取指针指向的值对应的结构体内容。
	for i := 0; i < t.NumField(); i++ { //NumField()可以获得该结构体的含有几个字段。
		//遍历结构体内的字段,通过t.Field(i).Tag.Get("json")可以获取到tag为json的字段。如果结构体的字段有多个tag,比如叫otherTag,同样可以通过t.Field(i).Tag.Get("otherTag")获得。
		fmt.Printf("结构体内第%v个字段 %v 对应的json tag是 %v , 还有otherTag? = %v \n", i+1, t.Field(i).Name, t.Field(i).Tag.Get("json"), t.Field(i).Tag.Get("otherTag"))
	}
}

func main() {
	j := J{
		a: "1",
		b: "2",
		C: "3",
		D: "4",
	}
	fmt.Printf("转为json前j结构体的内容 = %+v\n", j)
	jsonInfo, _ := json.Marshal(j)
	fmt.Printf("转为json后的内容 = %+v\n", string(jsonInfo))

    //printTag(&j)
}

输出

转为json前j结构体的内容 = {a:1 b:2 C:3 D:4}
转为json后的内容 = {"C":"3","DD":"4"}
  • 结构体里定义了四个字段,分别对应 小写无tag小写+tag大写无tag大写+tag
  • 转为json后首字母小写的不管加不加tag都不能转为json里的内容,而大写的加了tag可以取别名,不加tagjson内的字段跟结构体字段原名一致

反射获取Tag

  • reflect.TypeOf(stru).Elem()获取指针指向的值对应的结构体内容。
  • NumField()可以获得该结构体的含有几个字段。
  • 遍历结构体内的字段,通过t.Field(i).Tag.Get(“json”)可以获取到tag为json的字段。
  • 如果结构体的字段有多个tag,比如叫otherTag,同样可以通过t.Field(i).Tag.Get(“otherTag”)获得。

输出

结构体内第1个字段 a 对应的json tag是  , 还有otherTag? =  
结构体内第2个字段 b 对应的json tag是 B , 还有otherTag? =  
结构体内第3个字段 C 对应的json tag是  , 还有otherTag? =  
结构体内第4个字段 D 对应的json tag是 DD , 还有otherTag? = good

Marshaler来做到不导出小写字段输出Json

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	name  string
	hobby string
}
func (p Person) MarshalJSON() ([]byte, error) {
	return []byte(`{"name":"`+p.name+`","hobby":"`+p.hobby+`"}`), nil
}

func main() {
	person := Person{name: "polarisxu", hobby: "Golang"}
	m, _ := json.Marshal(person)
	fmt.Printf("%s", m)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值