go的反射
最近在学习go的反射,做一下笔记
基本概念
func reflectionDemo(a interface{}) {
// 获取类型
t0 := reflect.TypeOf(a)
fmt.Printf("type of a is:%v\n", t0)
// 获取值
v := reflect.ValueOf(a)
// 通过值获取类型
t1 := v.Type()
fmt.Printf("type of a is:%v\n", t1)
// 通过类型获得分类
kind := t1.Kind()
// 通过分类来判断是什么类型的
switch kind {
// 结构体
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
//打印字段的名称、类型以及值
fmt.Printf("name:%s type:%v value:%v\n",
t1.Field(i).Name, field.Type().Kind(), field.Interface())
}
// int类型
case reflect.Int:
fmt.Printf("%d\n",v)
// string类型
case reflect.String:
fmt.Printf("%s\n",v)
// 其他补充
default:
fmt.Printf("other\n")
}
}
实践
因为之前都是写java,访问数据库select的话框架会直接反解成java对象
写一个简单的查询数据库反解成对象
数据库建表语句
CREATE TABLE `mysql`.`student` (
`id` int(10) NOT NULL auto_increment,
`name` varchar(255) NULL DEFAULT NULL,
`age` int(10) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB character set= utf8mb4 COMMENT='学生表'
go代码
// Student对象 通过tag为数据库的列名,必须严格对应
type Student struct {
Id int `db:"id"`
Name string `db:"name"`
Age int `db:"age"`
}
const (
DBHostsIp = "127.0.0.1:3306"
DBUserName = "root"
DBPassWord = "123456"
DBName = "mysql"
)
func main() {
db, err := sql.Open("mysql", DBUserName+":" +DBPassWord+"@tcp("+DBHostsIp+")/"+DBName) // 设置连接数据库的参数
CheckErr(err)
defer db.Close() //关闭数据库
query(db, &Student{})
}
//查询demo
func query(db *sql.DB, target interface{}) []interface{} {
// 获取值
v := reflect.ValueOf(target).Elem()
// 获取类型
t := v.Type()
// rows:返回查询操作的结果集
rows, err := db.Query("SELECT * FROM student")
CheckErr(err)
cols, _ := rows.Columns()
// 用一个列名:索引的map保存信息
colsMap := make(map[string]int)
for i := 0; i < len(cols); i++ {
colsMap[cols[i]] = i
}
// 这里表示一行所有列的值,用[]byte表示
vals := make([][]byte, len(cols))
// 这里表示一行填充数据
line := make([]interface{}, len(cols))
// 这里scans引用vals,把数据填充到[]byte里
for k, _ := range vals {
line[k] = &vals[k]
}
i := 0
var resList []interface{}
for rows.Next() {
// 调用反射创建新对象
newStruc := reflect.New(t)
// 填充数据
rows.Scan(line...)
// 把vals中的数据复制到row中
for index, v := range line {
t := reflect.TypeOf(v)
fmt.Printf("type of a is:%v\n", t)
fmt.Println("---", cols[index])
}
// 默认接收的都是byte[],通过类的信息,将byte转换成对应的类型
numField := v.NumField()
for i := 0; i < numField; i++ {
// 通过类型获取字段
field := t.Field(i)
// 字段的名字
name := field.Name
// 通过字段获取db的Tag
colName := field.Tag.Get("db")
// 获取新对象中对应的字段
turlyField := newStruc.Elem().FieldByName(name)
if index, ok := colsMap[colName]; ok {
fmt.Println("print", colName)
switch field.Type.Kind() {
case reflect.String:
turlyField.SetString(string(vals[index]))
case reflect.Int:
value, err := strconv.Atoi(string(vals[index]))
if err == nil {
turlyField.SetInt(int64(value))
}
default:
fmt.Println("other")
}
}
}
resList = append(resList, newStruc)
i++
}
/**
* 结果如下
* &{1 小明 20}
* &{2 小红 18}
* &{3 大明 50}
*/
for _,value := range resList {
fmt.Println(value)
}
return resList
}