• golang面试题:reflect(反射包)如何获取字段tag​?为什么json包不能导出私有变量的tag?


    在这里插入图片描述

    问题

    json包里使用的时候,会结构体里的字段边上加tag,有没有什么办法可以获取到这个tag的内容呢?

    举例

    tag信息可以通过反射(reflect包)内的方法获取,通过一个例子加深理解。

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    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{}) {
        t := reflect.TypeOf(stru).Elem()
        for i := 0; i < t.NumField(); i++ {
            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",
        }
        printTag(&j)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    输出

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

    解释

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

    再补一句

    上篇文章 提到json包不能导出私有变量的tag是因为取不到反射信息的说法,但是直接取t.Field(i).Tag.Get(“json”)却可以获取到私有变量的json字段,是为什么呢?

    其实准确的说法是,json包里不能导出私有变量的tag是因为json包里认为私有变量为不可导出的Unexported,所以跳过获取名为json的tag的内容。

    具体可以看/src/encoding/json/encode.go:1070的代码。

    func typeFields(t reflect.Type) []field {
        // 注释掉其他逻辑...
        // 遍历结构体内的每个字段
        for i := 0; i < f.typ.NumField(); i++ {
            sf := f.typ.Field(i)
            isUnexported := sf.PkgPath != ""
            // 注释掉其他逻辑...
            if isUnexported {
                // 如果是不可导出的变量则跳过
                continue
            }
            // 如果是可导出的变量(public),则获取其json字段
            tag := sf.Tag.Get("json")
            // 注释掉其他逻辑...
        } 
        // 注释掉其他逻辑... 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    接口测试很难?3分钟带你入门接口自动化测试
    Jenkis 配置钉钉通知
    ExcelPatternTool: Excel表格-数据库互导工具
    【SA8295P 源码分析 (一)】76 - Thermal 功耗 之 /dev/thermalmgr 相关调试命令汇总
    Jimmer: 一个面向Java和Kotlin的革命性ORM
    [附源码]计算机毕业设计毕业生就业管理系统Springboot程序
    如何利用Python实现熵权法?
    【操作系统-IO管理】IO层次结构
    Golang代码漏洞扫描工具介绍——govulncheck
    ​@Cacheable 注解​
  • 原文地址:https://blog.csdn.net/m0_73728511/article/details/132817327