go基础-18.反射

news/2024/9/24 11:15:09

类型判断

判断一个变量是否是结构体,切片,map

package mainimport ("fmt""reflect"
)func refType(obj any) {typeObj := reflect.TypeOf(obj)fmt.Println(typeObj, typeObj.Kind())// 去判断具体的类型switch typeObj.Kind() {case reflect.Slice:fmt.Println("切片")case reflect.Map:fmt.Println("map")case reflect.Struct:fmt.Println("结构体")case reflect.String:fmt.Println("字符串")}
}func main() {refType(struct {Name string}{Name: "枫枫"})name := "枫枫"refType(name)refType([]string{"枫枫"})
}

通过反射获取值

func refValue(obj any) {value := reflect.ValueOf(obj)fmt.Println(value, value.Type())switch value.Kind() {case reflect.Int:fmt.Println(value.Int())case reflect.Struct:fmt.Println(value.Interface())case reflect.String:fmt.Println(value.String())}
}

通过反射修改值

注意,如果需要通过反射修改值,必须要传指针,在反射中使用Elem取指针对应的值

func refSetValue(obj any) {value := reflect.ValueOf(obj)elem := value.Elem()// 专门取指针反射的值switch elem.Kind() {case reflect.String:elem.SetString("枫枫知道")}
}func main() {name := "枫枫"refSetValue(&name)fmt.Println(name)
}

结构体反射

读取json标签对应的值,如果没有就用属性的名称

package mainimport ("fmt""reflect"
)type Student struct {Name stringAge  int `json:"age"`
}func main() {s := Student{Name: "枫枫知道",Age:  24,}t := reflect.TypeOf(s)v := reflect.ValueOf(s)for i := 0; i < t.NumField(); i++ {field := t.Field(i)jsonField := field.Tag.Get("json")if jsonField == "" {// 说明json的tag是空的jsonField = field.Name}fmt.Printf("Name: %s, type: %s, json: %s, value: %v\n", field.Name, field.Type, jsonField, v.Field(i))}
}

当然了,我们写的这个都很简单了,没有处理-和omitempty的情况

修改结构体中某些值

例如,结构体tag中有big的标签,就将值大写

package mainimport ("fmt""reflect""strings"
)type Student struct {Name1 string `big:"-"`Name2 string
}func main() {s := Student{Name1: "fengfeng",Name2: "zhangsan",}t := reflect.TypeOf(s)v := reflect.ValueOf(&s).Elem()for i := 0; i < t.NumField(); i++ {field := t.Field(i)bigField := field.Tag.Get("big")// 判断类型是不是字符串if field.Type.Kind() != reflect.String {continue}if bigField == "" {continue}// 修改值valueFiled := v.Field(i)valueFiled.SetString(strings.ToTitle(valueFiled.String()))}fmt.Println(s)
}

调用结构体方法

如果结构体有call这个名字的方法,就执行它

package mainimport ("fmt""reflect"
)type Student struct {Name stringAge  int
}func (Student) See(name string) {fmt.Println("see name:", name)
}func main() {s := Student{Name: "fengfeng",Age:  21,}t := reflect.TypeOf(s)v := reflect.ValueOf(s)for i := 0; i < t.NumMethod(); i++ {methodType := t.Method(i)fmt.Println(methodType.Name, methodType.Type)if methodType.Name != "See" {continue}methodValue := v.Method(i)methodValue.Call([]reflect.Value{reflect.ValueOf("枫枫"), // 注意这里的类型})}
}

orm的一个小案例

package mainimport ("errors""fmt""reflect""strings"
)type Student struct {Name string `feng-orm:"name"`Age  int    `feng-orm:"age"`
}type UserInfo struct {Id   int    `feng-orm:"id"`Name string `feng-orm:"name"`Age  int    `feng-orm:"age"`
}func Find(obj any, query ...any) (sql string, err error) {// Find(Student, "name = ?", "fengfeng")// 希望能够生成 select name, age from  where  name = 'fengfeng't := reflect.TypeOf(obj)//v := reflect.ValueOf(obj)// 首先得是结构体对吧if t.Kind() != reflect.Struct {err = errors.New("非结构体")return}// 拿全部字段// 拼接条件// 第二个参数,中的问号,就决定后面还能接多少参数var where stringif len(query) > 0 {// 有第二个参数,校验第二个参数中的?个数,是不是和后面的个数一样q := query[0] // 理论上还要校验第二个参数的类型if strings.Count(q.(string), "?")+1 != len(query) {err = errors.New("参数个数不对")return}// 拼接where语句// 将?号带入后面的参数for _, a := range query[1:] {// 替换q// 这里要判断a的类型at := reflect.TypeOf(a)switch at.Kind() {case reflect.Int:q = strings.Replace(q.(string), "?", fmt.Sprintf("%d", a.(int)), 1)case reflect.String:q = strings.Replace(q.(string), "?", fmt.Sprintf("'%s'", a.(string)), 1)}}where += "where " + q.(string)}// 如果没有第二个参数,就是查全部// 拼接select// 拿所有字段,取feng-orm对应的值var columns []stringfor i := 0; i < t.NumField(); i++ {field := t.Field(i)f := field.Tag.Get("feng-orm")// 不考虑是空的情况columns = append(columns, f)}// 结构体的小写名字+s做表名name := strings.ToLower(t.Name()) + "s"// 拼接最后的sqlsql = fmt.Sprintf("select %s from %s %s", strings.Join(columns, ","), name, where)return
}func main() {sql, err := Find(Student{}, "name = ? and age = ?", "枫枫", 23)fmt.Println(sql, err) // select name,age from students where name = '枫枫' and age = 23sql, err = Find(UserInfo{}, "id = ?", 1)fmt.Println(sql, err) // select id,name,age from userinfos where id = 1
}

对反射的一些建议

如果是写一下框架,偏底层工具类的操作

不用反射确实不太好写,但是如果是在业务上,大量使用反射就不太合适了

因为反射的性能没有正常代码高,会慢个一到两个数量级

使用反射可读性也不太好,并且也不能在编译期间发生错误

参考文档

go反射 https://blog.csdn.net/a1053765496/article/details/129904985

反射 https://www.liwenzhou.com/posts/Go/reflect/

解析sql案例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/64097.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

Leetcode 445. 两数相加 II

1.题目基本信息 1.1.题目描述 给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外,这两个数字都不会以零开头。 1.2.题目地址 https://leetcode.cn/problems/add…

Windows命令:时间延迟命令

延迟一段时间再执行下一条命令”。 一、利用ping实现延迟命令 这种延时手段是不精确的,因为每一次ping通的延迟不一样。 1、示例chcp 65001 @echo off echo 延时前:%time% ping /n 3 127.0.0.1 >nul echo 延时后:%time% pause 参数/n表示ping通的次数。127.0.0.1是本机ip…

电力施工作业绝缘手套识别系统

电力施工作业绝缘手套识别系统对电力作业人员在电力设备上进行施工作业时是否佩戴绝缘手套进行识别分析,当电力施工作业绝缘手套识别系统检测到作业人员未佩戴绝缘手套时立即抓拍存档同步回传给后台监控人员,提醒相关人员及时制止,及时规避更危险的触电事故发生。电力施工作…

sicp每日一题[2.24-2.27]

2.24-2.26没什么代码量,所以跟 2.27 一起发吧。Exercise 2.24Suppose we evaluate the expression (list 1 (list 2 (list 3 4))). Give the result printed by the interpreter, the corresponding box-and-pointer structure, and the interpretation of this as a tree (as…

ansible-cmdb简单使用

1、安装 官方:https://ansible-cmdb.readthedocs.io/en/latest/ wget https://github.com/fboender/ansible-cmdb/releases/download/1.27/ansible-cmdb-1.27-2.noarch.rpm yum -y install ./ansible-cmdb-1.27-2.noarch.rpm2、使用 首先,为你的主机生成 Asible 输出: mkdir…

ToEasy利用99元阿里云服务器内网穿透的实操过程

一、准备工作: 1、阿里云99元服务器(安装Windows)或者其他windows云服务器 2、frp内网穿透软件 3、数据库MSSQL 2014绿色版 4、ToEasy服务器和客户端软件 二、内网穿透设置 解压frp软件后,打开配置文件frps.toml和frpc.toml进行设置。 1、服务端(frps.toml)#bindAddr = &…

PARTIV-Oracle数据库存储结构-逻辑存储结构

12.逻辑存储结构 12.1. 逻辑存储结构简介 Oracle数据库为数据库中的所有数据分配逻辑空间。数据库空间分配的逻辑单位是数据块、区间、段和表空间。在物理层面,数据存储在磁盘上的数据文件中(见第11章“物理存储结构”)。数据文件中的数据存储在操作系统块中。图12-1是物理和…

MySQL性能优化

性能调优 MySQL调优的五个维度 对于MySQL的性能优化,其实也可以从多个维度出发,共计优化项如下:①客户端与连接层的优化:调整客户端DB连接池的参数和DB连接层的参数。 ②MySQL结构的优化:合理的设计库表结构,表中字段根据业务选择合适的数据类型、索引。 ③MySQL参数优化…