与ChatGpt聊天,学习golang标签的反射机制

文章介绍了如何使用Go语言的反射(reflect)包来访问结构体的json标签,并讨论了性能优化,包括避免不必要的JSON序列化以及通过缓存来提升效率。此外,还解释了如何获取自定义标签,如neo4j-column,并提供了相关代码示例。
摘要由CSDN通过智能技术生成

与ChatGpt聊天,学习golang标签的反射机制

ChatGPT火了以后,本拐先是恐惧,之后是拥抱。

最近很多编程知识的学习,都是通过 chatgpt来搞定。

众所周知,本拐就是一个啥技术都半斤八两的程序员,这次,为了学习golang中一些反射的机制,主要是tag属性,本拐又与chatgpt来了一次深入交流。

过程

本拐确实对golang中的tag属性所知甚少,所以先从json开始吧,挖个坑先。



 golang 中怎么用反射取到json

在 Golang 中,可以使用反射机制来获取一个对象的 json 表示。假设我们有一个结构体 Person 如下:

type Person struct {
    Name    string    `json:"name"`
    Age     int       `json:"age"`
    Address string    `json:"address"`
}

然后,我们可以使用以下代码来将一个 Person 对象转换成 json 字符串,并使用反射机制获取它:

import (
    "encoding/json"
    "reflect"
)

func main() {
    person := Person{"John", 30, "123 Main St."}

    // 将 person 转换为 json 字符串
    jsonBytes, _ := json.Marshal(person)
    jsonString := string(jsonBytes)

    // 通过反射获取 json 中的字段值
    value := reflect.ValueOf(person)
    for i := 0; i < value.NumField(); i++ {
        field := value.Type().Field(i)
        fieldName := field.Tag.Get("json")
        fieldValue := value.Field(i).Interface()
        fmt.Printf("%s: %v\n", fieldName, fieldValue)
    }
}

输出将会是:

name: John
age: 30
address: 123 Main St.

在这个例子中,我们使用 encoding/json 包将 person 对象转换为 json 字符串。然后,我们使用 reflect 包获取结构体的值,通过循环遍历所有字段并使用 Tag.Get 方法获取字段的 json 标签,最后使用 Field(i).Interface() 获取字段的值

c827bbd42a69008ec6787e08addc67b2.jpeg




嘿嘿,这个问题回答的可不漂亮啊,本拐成功抓住了其中的不足。

 这个方式是不是有些性能损失?因为 json.Marshal(person) 时已经读取了一次

chatgpt成功地get到了我的点。

 是的,您是正确的。在上面的示例中,我们先将 person 对象转换为 JSON 字符串,然后再通过反射机制解析该字符串,这样可能会导致一些性能损失。

如果您需要获取结构体字段的 JSON 标签,而不必将整个结构体转换为 JSON 字符串,您可以使用 reflect 包中的 Type 方法来获取结构体类型,并通过 Type 方法中的 Field 方法获取字段的类型信息。然后,您可以使用 StructTag 方法获取该字段的标签信息,进而获取 JSON 标签。

下面是一个示例:

import (
    "reflect"
)

func main() {
    person := Person{"John", 30, "123 Main St."}

    t := reflect.TypeOf(person)
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        jsonTag := field.Tag.Get("json")
        fmt.Printf("%s: %s\n", field.Name, jsonTag)
    }
}

在这个示例中,我们使用 reflect 包中的 Type 方法获取 person 对象的类型信息,并通过 Type 方法中的 Field 方法获取字段的类型信息。然后,我们使用 StructTag 方法获取该字段的标签信息,并通过 Tag.Get 方法获取 JSON 标签。

这种方法避免了将整个结构体转换为 JSON 字符串的开销,因此可能会更加高效。

feea5efe38c8a22ea3a2c77f230fdf4a.jpeg


本拐毕竟是乱炖程序员,所以,优化还是要有的。

 如果 这个方法被反复调用,加map是否可以提高他的性能

ChatGPT 一如既往的聪明

 如果您需要在多个不同的地方反复获取结构体字段的 JSON 标签,可以考虑将字段的 JSON 标签缓存到一个 map 中,以提高性能。这样,当需要获取 JSON 标签时,只需要从缓存中查找即可,而不需要每次都使用反射获取。

下面是一个示例:

import (
    "reflect"
)

var jsonTagCache = make(map[string]string)

func getJSONTag(field reflect.StructField) string {
    if jsonTag, ok := jsonTagCache[field.Name]; ok {
        return jsonTag
    }

    jsonTag := field.Tag.Get("json")
    jsonTagCache[field.Name] = jsonTag

    return jsonTag
}

func main() {
    person := Person{"John", 30, "123 Main St."}

    t := reflect.TypeOf(person)
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        jsonTag := getJSONTag(field)
        fmt.Printf("%s: %s\n", field.Name, jsonTag)
    }
}

在这个示例中,我们定义了一个全局变量 jsonTagCache,它是一个 map[string]string 类型的缓存。然后,我们定义了一个函数 getJSONTag,该函数接受一个 reflect.StructField 类型的参数,并返回该字段的 JSON 标签。在该函数中,我们首先从缓存中查找 JSON 标签,如果找到了就直接返回,否则就使用 Tag.Get 方法获取 JSON 标签,并将其添加到缓存中,然后返回 JSON 标签。

在 main 函数中,我们使用 reflect 包中的 Type 方法获取 person 对象的类型信息,并通过 Type 方法中的 Field 方法获取字段的类型信息。然后,我们调用 getJSONTag 函数获取字段的 JSON 标签。

通过缓存 JSON 标签,可以避免每次都使用反射获取标签的开销,因此可以提高性能。但是请注意,如果您在处理的结构体类型非常多,缓存可能会占用大量内存。如果您需要处理大量的结构体类型,请考虑限制缓存的大小或使用 LRU 缓存等方式来优化缓存的性能和内存使用。

3f905f0cbd2a764125fc44eec225d3f3.jpeg


好了,终极目的要达成了,问一下自定义标签的问题。

 我如果 把json换成我的一个自定义标签,比如neo4j-colum 是不是也可以用类似的机制来实现类似功能。

 是的,您可以使用类似的机制来获取结构体字段的自定义标签,例如 neo4j-column 标签。

只需要将 getJSONTag 函数中的 Tag.Get("json") 方法替换为 Tag.Get("neo4j-column") 即可。具体来说,您可以按照以下方式修改 getJSONTag 函数:

func getCustomTag(field reflect.StructField, tagName string) string {
    cacheKey := fmt.Sprintf("%s_%s", field.Name, tagName)
    if tag, ok := customTagCache[cacheKey]; ok {
        return tag
    }

    tag := field.Tag.Get(tagName)
    customTagCache[cacheKey] = tag

    return tag
}

在这个示例中,我们将 getJSONTag 函数重命名为 getCustomTag,并将 Tag.Get("json") 方法替换为 Tag.Get(tagName) 方法,其中 tagName 是您要获取的自定义标签名称。我们还修改了缓存键的生成方式,将字段名和标签名组合在一起作为缓存键,以避免不同的标签名使用相同的缓存键。

您可以按照以下方式使用 getCustomTag 函数来获取结构体字段的 neo4j-column 标签:

person := Person{"John", 30, "123 Main St."}

t := reflect.TypeOf(person)
for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    columnTag := getCustomTag(field, "neo4j-column")
    fmt.Printf("%s: %s\n", field.Name, columnTag)
}

在这个示例中,我们使用 getCustomTag 函数获取字段的 neo4j-column 标签。

16061d05c7b9651a6b313f47b6200a70.jpeg

注意这里,chatgpt自动纠正了错误的拼写

结论

ChatGPT火了以后,很多朋友说这个东西没有什么用,或是用处不大。

本拐以为,用好这个东西,在于提问的技巧,所以,用这个文章做了一个引子。

您觉得如何?

关于老拐瘦

中年争取不油不丧积极向上的码农一名

咖啡,摄影,骑行,音乐

样样通,样样松

喜欢可以关注一下公众号 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值