变量的外在机制
类型信息:是动态的元信息,是事后定义好的
值信息:是程序运行过程中动静扭转的
反射的应用
获取类型信息:reflect.TypeOf,是动态的
获取值信息:reflect.ValueOf,是动静的
反射获取 interface 值信息
package main
import (
"fmt"
"reflect"
)
// 反射获取 interface 值信息
func reflect_value(a interface{}) {v := reflect.ValueOf(a)
fmt.Println(v)
k := v.Kind()
fmt.Println(k)
switch k {
case reflect.Float64:
fmt.Println("a 是:", v.Float())
}
}
func main() {
var x float64 = 3.4
reflect_value(x)
}
反射批改值信息
package main
import (
"fmt"
"reflect"
)
// 反射批改值
func reflect_set_value(a interface{}) {v := reflect.ValueOf(a)
k := v.Kind()
switch k {
case reflect.Float64:
// 反射批改值
v.SetFloat(6.9)
fmt.Println("a is", v.Float())
case reflect.Ptr:
// Elem() 获取地址指向的值
v.Elem().SetFloat(7.9)
fmt.Println("case:", v.Elem().Float())
// 地址
fmt.Println(v.Pointer())
}
}
func main() {
var x float64 = 3.4
// 反射认为上面是指针类型,不是 float 类型
reflect_set_value(&x)
fmt.Println("main:", x)
}
构造体与反射
查看类型、字段和办法
package main
import (
"fmt"
"reflect"
)
// 定义构造体
type User struct {
Id int
Name string
Age int
}
// 绑办法
func (u User) Hello() {fmt.Println("Hello")
}
// 传入 interface{}
func Poni(o interface{}) {t := reflect.TypeOf(o)
fmt.Println("类型:", t)
fmt.Println("字符串类型:", t.Name())
// 获取值
v := reflect.ValueOf(o)
fmt.Println(v)
// 能够获取所有属性
// 获取构造体字段个数:t.NumField()
for i := 0; i < t.NumField(); i++ {
// 取每个字段
f := t.Field(i)
fmt.Printf("%s : %v", f.Name, f.Type)
// 获取字段的值信息
// Interface():获取字段对应的值
val := v.Field(i).Interface()
fmt.Println("val :", val)
}
fmt.Println("================= 办法 ====================")
for i := 0; i < t.NumMethod(); i++ {m := t.Method(i)
fmt.Println(m.Name)
fmt.Println(m.Type)
}
}
func main() {u := User{1, "zs", 20}
Poni(u)
}
查看匿名字段
package main
import (
"fmt"
"reflect"
)
// 定义构造体
type User struct {
Id int
Name string
Age int
}
// 匿名字段
type Boy struct {
User
Addr string
}
func main() {m := Boy{User{1, "zs", 20}, "bj"}
t := reflect.TypeOf(m)
fmt.Println(t)
// Anonymous:匿名
fmt.Printf("%#v\n", t.Field(0))
// 值信息
fmt.Printf("%#v\n", reflect.ValueOf(m).Field(0))
}
批改构造体的值
package main
import (
"fmt"
"reflect"
)
// 定义构造体
type User struct {
Id int
Name string
Age int
}
// 批改构造体值
func SetValue(o interface{}) {v := reflect.ValueOf(o)
// 获取指针指向的元素
v = v.Elem()
// 取字段
f := v.FieldByName("Name")
if f.Kind() == reflect.String {f.SetString("kuteng")
}
}
func main() {u := User{1, "5lmh.com", 20}
SetValue(&u)
fmt.Println(u)
}
调用办法
package main
import (
"fmt"
"reflect"
)
// 定义构造体
type User struct {
Id int
Name string
Age int
}
func (u User) Hello(name string) {fmt.Println("Hello:", name)
}
func main() {u := User{1, "5lmh.com", 20}
v := reflect.ValueOf(u)
// 获取办法
m := v.MethodByName("Hello")
// 构建一些参数
args := []reflect.Value{reflect.ValueOf("6666")}
// 没参数的状况下:var args2 []reflect.Value
// 调用办法,须要传入办法的参数
m.Call(args)
}
获取字段的 tag
package main
import (
"fmt"
"reflect"
)
type Student struct {Name string `json:"name1" db:"name2"`}
func main() {
var s Student
v := reflect.ValueOf(&s)
// 类型
t := v.Type()
// 获取字段
f := t.Elem().Field(0)
fmt.Println(f.Tag.Get("json"))
fmt.Println(f.Tag.Get("db"))
}
实例
办法
package common
import (
"errors"
"reflect"
"strconv"
"time"
)
// 依据构造体中 sql 标签映射数据到构造体中并且转换类型
func DataToStructByTagSql(data map[string]string, obj interface{}) {objValue := reflect.ValueOf(obj).Elem()
for i := 0; i < objValue.NumField(); i++ {
// 获取 sql 对应的值
value := data[objValue.Type().Field(i).Tag.Get("sql")]
// 获取对应字段的名称
name := objValue.Type().Field(i).Name
// 获取对应字段类型
structFieldType := objValue.Field(i).Type()
// 获取变量类型,也能够间接写 "string 类型"
val := reflect.ValueOf(value)
var err error
if structFieldType != val.Type() {
// 类型转换
val, err = TypeConversion(value, structFieldType.Name()) // 类型转换
if err != nil {}}
// 设置类型值
objValue.FieldByName(name).Set(val)
}
}
// 类型转换
func TypeConversion(value string, ntype string) (reflect.Value, error) {
if ntype == "string" {return reflect.ValueOf(value), nil
} else if ntype == "time.Time" {t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
return reflect.ValueOf(t), err
} else if ntype == "Time" {t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
return reflect.ValueOf(t), err
} else if ntype == "int" {i, err := strconv.Atoi(value)
return reflect.ValueOf(i), err
} else if ntype == "int8" {i, err := strconv.ParseInt(value, 10, 64)
return reflect.ValueOf(int8(i)), err
} else if ntype == "int32" {i, err := strconv.ParseInt(value, 10, 64)
return reflect.ValueOf(int64(i)), err
} else if ntype == "int64" {i, err := strconv.ParseInt(value, 10, 64)
return reflect.ValueOf(i), err
} else if ntype == "float32" {i, err := strconv.ParseFloat(value, 64)
return reflect.ValueOf(float32(i)), err
} else if ntype == "float64" {i, err := strconv.ParseFloat(value, 64)
return reflect.ValueOf(i), err
}
//else if ....... 减少其余一些类型的转换
return reflect.ValueOf(value), errors.New("未知的类型:" + ntype)
}
调用
package main
import (
"fmt"
"github.com/student/1129/common"
)
//Product Product 定义一个构造体
type Product struct {
ID int64 `json:"id" sql:"id"`
ProductClass string `json:"ProductClass" sql:"ProductClass"`
ProductName string `json:"ProductName" sql:"productName"`
ProductNum int64 `json:"ProductNum" sql:"productNum"`
ProductImage string `json:"ProductImage" sql:"productImage"`
ProductURL string `json:"ProductUrl" sql:"productUrl" `
}
func main() {
// 这块是模仿 mysql 获取单条的数据反射到构造体
data := map[string]string{"id": "1", "ProductClass": "blog", "productName": "5lmh.com", "productNum": "40", "productImage": "http://www.5lmh.com/", "productUrl": "http://www.5lmh.com/"}
productResult := &Product{}
common.DataToStructByTagSql(data, productResult)
fmt.Println(*productResult)
// 这块是模仿 mysql 获取所有的数据反射到构造体
Alldata := []map[string]string{{"id": "1", "ProductClass": "blog", "productName": "5lmh.com", "productNum": "40", "productImage": "http://www.5lmh.com/", "productUrl": "http://www.5lmh.com/"},
{"id": "2", "ProductClass": "blog", "productName": "5lmh.com", "productNum": "40", "productImage": "http://www.5lmh.com/", "productUrl": "http://www.5lmh.com/"},
}
var productArray []*Product
for _, v := range Alldata {Allproduct := &Product{}
common.DataToStructByTagSql(v, Allproduct)
productArray = append(productArray, Allproduct)
}
for _, vv := range productArray {fmt.Println(vv)
}
}