Gorm之事务 | 青训营笔记

71 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天

go语言提供了一种机制,在编译时不知道类型的情况下,可更新变量,在运行时查看值,调用方法以及直接对他们的布局进行操作。这种机制称为反射(reflection)。

为什么使用反射

使用空接口,可以传任意类型的数据,但是不能修改原始值

package main
import "fmt"
type User struct {
  Name string
  Age  int
}
func Print(inter interface{}) {
  switch x := inter.(type) {
  case User:
    x.Name = "张三"
    fmt.Println(x.Name, x.Age)
  }
  //user := inter.(User)
  //user.Name = "xxx"
}
func PPrint(user *User) {
  user.Name = "王五"
}
func main() {
  user := User{"枫枫", 21}
  Print(user)
  fmt.Println(&user)
  //PPrint(&user)
  //fmt.Println(user)
}

用反射就能动态修改原始数据

反射的优缺点

  1. 可以动态修改数据的值

  1. 性能问题
  2. 可读性不太好

reflect包

两个很重要的方法 TypeOf,ValueOf

package main
import (
  "fmt"
  "reflect"
)
type User struct {
  Name string `json:"name" feng:"name_xxx"`
  Age  int    `json:"age" feng:"age_xxx"`
}
func FPrint(inter interface{}) {
  t := reflect.TypeOf(inter)
  v := reflect.ValueOf(inter)
  //fmt.Println(t.Kind()) // 获取这个接口的底层类型
  //fmt.Println(t.Elem()) // 变量的原始类型
  for i := 0; i < t.NumField(); i++ {
    //fmt.Println()
    // 字段的类型
    // 字段名
    // 字段的值
    // 字段的tag
    fmt.Println(
      t.Field(i).Type,
      t.Field(i).Name,
      v.Field(i),
      t.Field(i).Tag.Get("feng"),
    )
  }
}
func main() {
  user := User{"枫枫", 21}
  FPrint(user)
}

修改结构体的数据

package main
import (
  "fmt"
  "reflect"
)
type User struct {
  Name string `json:"name" feng:"name_xxx"`
  Age  int    `json:"age" feng:"age_xxx"`
}
func FPrint(inter interface{}) {
  v := reflect.ValueOf(inter)
  e := v.Elem()  // 必须用这个
  e.FieldByName("Name").SetString("枫枫知道")
}
func main() {
  user := User{"枫枫", 21}
  FPrint(&user)  // 必须传指针
  fmt.Println(user)
}