golang反射

简介: golang反射

公众号merlinsea


  • 反射的介绍
  • 反射可以在运行时动态获取变量的各种信息,比如变量的类型(type)和变量的类别(kind)
  • Type 有 Student结构体,Monster结构体等等
  • Kind 有 结构体,指针等
  • 反射还可以获取结构体变量本身的信息,比如结构体变量的字段和方法
  • 反射可以修改变量的值和调用关联的方法
  • 反射在golang中主要是通过reflect.Value类型来操作的!!!!


640.jpg

  • interface{} 、 原始数据类型 、reflect.Value类型的相互转换


640.jpg

import (
   "fmt"
   "reflect"
)
type Stu struct {
   Name string
   Age  int
}
func main() {
   stu := Stu{
      Name: "lianglin",
      Age:  19,
   }
   rVal := reflect.ValueOf(stu) // 通过ValueOf方法得到reflect.Value类型
   fmt.Printf("rVal 类型 = %T\n", rVal)
   rType := rVal.Type()
   fmt.Printf("rType = %v , rType 类型 = %T\n", rType, rType) //rType = main.Stu , rType 类型 = *reflect.rtype
   kind := rVal.Kind()
   fmt.Printf("kind = %v , kind 类型 = %T\n", kind, kind) //kind = struct , kind 类型 = reflect.Kind
   iVal := rVal.Interface() // 通过调用Interface()方法得到interface{}类型
   fmt.Printf("iVal 类型 = %T\n", iVal)
   v := iVal.(Stu) // 通过类型断言转回Stu类型
   fmt.Printf("v 类型 = %T\n", v)
}


  • 通过反射改变变量的值    
  • 注意点:
  • 传递的给reflect.ValueOf()的的v必须是指针类型,即地址类型
  • 在修改的时候需要先通过Elem()获取到指针指向的地址内容


func reflectModify(b interface{}) {
    // 这里要求b必须是一个指针类型,可以通过Kind()进行判断
   rVal := reflect.ValueOf(b)
   //Elem返回v持有的接口保管的值的Value封装,或者v持有的指针指向的值的Value封装
   if rVal.Kind() == reflect.Pointer {
      // 当rVal是一个指针类型当时候,用Elem()来取到指针指向的地址内容
      rVal.Elem().SetInt(20)
   } else{
      fmt.Println("传入的变量不是指针类型,因此不能修改变量的值")
   }
}
func main() {
   var num int = 10
   // 这里传入地址是希望函数内的改变可以影响函数外部
   reflectModify(&num)
   fmt.Println("num=", num) // 20
}


  • 通过反射调用结构体的方法


import (
   "fmt"
   "reflect"
)
//定义了一个Monster结构体
type Monster struct {
   Name  string `json:"name"`
   Age   int `json:"monster_age"`
   Score float32 `json:"成绩"`
   Sex   string
}
//方法,返回两个数的和
func (s Monster) GetSum(n1, n2 int) int {
   return n1 + n2
}
//方法, 接收四个值,给s赋值
func (s Monster) Set(name string, age int, score float32, sex string) {
   s.Name = name
   s.Age = age
   s.Score = score
   s.Sex = sex
}
//方法,显示s的值
func (s Monster) Print() {
   fmt.Println("---start~----")
   fmt.Println(s)
   fmt.Println("---end~----")
}
func TestStruct(a interface{}) {
   //获取reflect.Type 类型,在获取字段标签的时候用上
   typ := reflect.TypeOf(a)
   //获取reflect.Value 类型
   val := reflect.ValueOf(a)
   //获取到a对应的类别
   kd := val.Kind()
   //如果传入的不是struct,就退出
   if kd !=  reflect.Struct {
      fmt.Println("expect struct")
      return
   }
   //获取到该结构体有几个字段
   num := val.NumField()
   fmt.Printf("struct has %d fields\n", num) //4
   //变量结构体的所有字段
   for i := 0; i < num; i++ {
      fmt.Printf("Field %d: 值为=%v\n", i, val.Field(i))
      //获取到struct标签, 注意需要通过reflect.Type来获取tag标签的值
      tagVal := typ.Field(i).Tag.Get("json")
      //如果该字段于tag标签就显示,否则就不显示
      if tagVal != "" {
         fmt.Printf("Field %d: tag为=%v\n", i, tagVal)
      }
   }
   //获取到该结构体有多少个方法
   numOfMethod := val.NumMethod()
   fmt.Printf("struct has %d methods\n", numOfMethod)
   //var params []reflect.Value
   //方法的排序默认是按照 函数名的排序(ASCII码)
   val.Method(1).Call(nil) //获取到第二个方法。调用它
   //调用结构体的第1个方法Method(0)
   var params []reflect.Value  //声明了 []reflect.Value
   params = append(params, reflect.ValueOf(10))
   params = append(params, reflect.ValueOf(40))
   res := val.Method(0).Call(params) //传入的参数是 []reflect.Value, 返回[]reflect.Value
   fmt.Println("res=", res[0].Int()) //返回结果, 返回的结果是 []reflect.Value*/
}
func main() {
   //创建了一个Monster实例
   var a Monster = Monster{
      Name:  "黄鼠狼精",
      Age:   400,
      Score: 30.8,
   }
   //将Monster实例传递给TestStruct函数
   TestStruct(a)  
}


相关文章
Golang反射---结构体的操作案例大全
Golang反射---结构体的操作案例大全
82 0
|
4月前
|
存储 人工智能 Go
golang 反射基本原理及用法
golang 反射基本原理及用法
35 0
|
7月前
|
JSON 监控 安全
Golang深入浅出之-Go语言中的反射(reflect):原理与实战应用
【5月更文挑战第1天】Go语言的反射允许运行时检查和修改结构,主要通过`reflect`包的`Type`和`Value`实现。然而,滥用反射可能导致代码复杂和性能下降。要安全使用,应注意避免过度使用,始终进行类型检查,并尊重封装。反射的应用包括动态接口实现、JSON序列化和元编程。理解反射原理并谨慎使用是关键,应尽量保持代码静态类型。
101 2
|
7月前
|
JSON 编译器 Go
Golang深入浅出之-结构体标签(Tags):JSON序列化与反射应用
【4月更文挑战第22天】Go语言结构体标签用于添加元信息,常用于JSON序列化和ORM框架。本文聚焦JSON序列化和反射应用,讨论了如何使用`json`标签处理敏感字段、实现`omitempty`、自定义字段名和嵌套结构体。同时,通过反射访问标签信息,但应注意反射可能带来的性能问题。正确使用结构体标签能提升代码质量和安全性。
330 0
|
存储 Java Go
Golang的反射reflect深入理解和示例
Golang的反射reflect深入理解和示例
|
7月前
|
存储 Go
Golang底层原理剖析之反射reflect
Golang底层原理剖析之反射reflect
85 0
|
存储 Go
反射三定律带你初步了解Golang反射的概念~
反射三定律带你初步了解Golang反射的概念~
深入了解Golang中的反射机制
深入了解Golang中的反射机制
146 0
|
Go 容器
经历这么多失败也值了, 我终于把掌握 golang 反射了, 总结几点经验
经历这么多失败也值了, 我终于把掌握 golang 反射了, 总结几点经验
265 0
经历这么多失败也值了, 我终于把掌握 golang 反射了, 总结几点经验