Go基础之--反射

反射:可以在运行时动态获取变量的相关信息

反射需要导入reflect

反射中重要函数的演示

反射有几下几个重要的函数: reflect.TypeOf :获取变量的类型,返回reflect.Type类型 reflect.ValueOf:获取变量的值,返回reflect.Value类型 reflect.Value.Kind:获取变量的类别,返回一个常量 reflect.Value.Interface():转换成interface{}类型

通过一个小例子来理解:

package main

import (
    "reflect"
    "fmt"
)

type Student struct{
    Name string
    Age int
}

func (s*Student) SetName(name string){
    s.Name="coders"
}

func (s*Student)SetAge(age int){
    s.Age = 23
}


func getTypeInfo(a interface{}){
    // 用于获取一个数据的数据类型
    typeInfo := reflect.TypeOf(a)
    kind := typeInfo.Kind()
    fmt.Println("kind of a :",kind)

    num := typeInfo.NumMethod() //获取当前数据有多少个方法
    fmt.Println("method num:",num)

    method,ok:=typeInfo.MethodByName("SetName") //获取是否有某个方法
    if !ok{
        fmt.Println("not have method SetName")
    }else{
        fmt.Println(method)
    }
}

func getAllMethod(a interface{}){
    // 用于获取变量下的所有方法
    typeInfo := reflect.TypeOf(a)
    num := typeInfo.NumMethod()
    for i:=0;i<num;i++ {
        method:= typeInfo.Method(i)
        fmt.Println(method)
    }
}

func testGetAllMethod()  {
    var stu Student
    getAllMethod(&stu)
}

func testGetTypeInfo(){
    var i int
    getTypeInfo(i) //获取的结果就是int

    var stu Student
    getTypeInfo(&stu) //获取的结果就是struct
    getAllMethod(&stu)

    var s []int
    getTypeInfo(s)  //获取的结果就是slice

    var a [5]int
    getTypeInfo(a)  //获取的结果就是array


}

func testGetValueInfo(){
    var i = 100
    valueInfo := reflect.ValueOf(i)
    tmp := valueInfo.Interface()  //转换成interface类型
    val := tmp.(int) //这里我是知道是int所以直接转换了
    fmt.Println("val:",val) //这里获取的还是100
    fmt.Println("val of valueInfo:",valueInfo.Int()) // 这里打印的也是100
    fmt.Println("type:",valueInfo.Type())
    fmt.Println("kind:",valueInfo.Kind())
}

func main(){
    testGetTypeInfo()
    testGetAllMethod()
    testGetValueInfo()
}

上面这个例子中演示了reflect.Value.Kind()可以返回int,struct,slice,array,当然这里可以返回的类型还有很多如下: Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer

获取变量的值

reflect.ValueOf(x).Float() reflect.ValueOf(x).Int() reflect.ValueOf(x).String() reflect.ValueOf(x).Bool()

这个功能在上面的代码中也有演示

通过反射来改变变量的值

reflect.Value.SetXX相关方法,如: reflect.Value.SetFloat():设置浮点数 reflect.Value.SetInt():设置整数 reflect.Value.SetString():设置字符串

通过下面一个简单的例子来演示:

package main

import (
    "reflect"
    "fmt"
)

func main() {
    var a float64
    fmt.Println(a)
    fv := reflect.ValueOf(a)
    fv.SetFloat(3.14)
    fmt.Println(a)
}

上面这段代码会提示如下错误:

这里需要知道的是我们的变量a是一个值类型的变量,我们通过reflect.valueOf传入的时候其实是传入的变量的拷贝,所以我们如果通过SetFloat给变量设置值的时候其实并不会生效,go这里已经替我考虑到了,所以给我们提示了上面这个错误信息,那是不是我们在reflect.Value的传入地址就可以了呢,我把上述代码中更改为:reflect.Value(&a),当我们运行后发现还是报了和上面相同的错误,这是为什么呢?

我们应该还记得如果是一个指针的时候我们赋值的时候是需要在指针的左边写个*符号,但是这是在反射里面我们怎么写星号,所以go在这里提供给我们另外一个方法,当我们通过调用SetFloat的时候用: fv.Elem().SetFloat(3.14)这种方式调用就ok了,完整的正确代码为:

package main

import (
    "reflect"
    "fmt"
)

func main() {
    var a float64
    fmt.Println(a)
    fv := reflect.ValueOf(&a)
    fv.Elem().SetFloat(3.14)
    fmt.Println(a)
}

反射操作结构体

reflect.Value.NumField():获取结构体中字段的个数 reflect.Value.Method(n).Call():调用结构体中的方法

package main

import (
    "reflect"
    "fmt"
)

type Student struct{
    Name string
    Age int
    Sex int
}

func (s *Student) Set(name string,age int,sex int){
    s.Name = name
    s.Age = age
    s.Sex = sex
}

func testStruct()  {
    var stu *Student = &Student{}
    stu.Set("coder",23,1)
    valueInfo := reflect.ValueOf(stu)

    fieldNum := valueInfo.Elem().NumField()
    fmt.Println("filed num:",fieldNum) //这里返回的结果是3

    sexValueInfo := valueInfo.Elem().FieldByName("Sex")
    fmt.Println("sex=",sexValueInfo.Int())
    sexValueInfo.SetInt(0) //这里是更改值
    fmt.Println(stu)
    setMethod := valueInfo.MethodByName("Set") //获取Set方法
    var params []reflect.Value
    name := "tom"
    age := 18
    sex:=2
    params = append(params,reflect.ValueOf(name),reflect.ValueOf(age),reflect.ValueOf(sex))
    setMethod.Call(params) //调用Set方法
    fmt.Println(stu) //将最开始的值已经更改了


}

func main() {
    testStruct()
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一个会写诗的程序员的博客

jQuery Validate自定义各种验证方法jQuery Validate自定义各种验证方法

972
来自专栏Golang语言社区

浅谈Go语言中的结构体struct &amp; 接口Interface &amp; 反射

结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套;

2164
来自专栏Golang语言社区

Go语言struct类型详解

struct Go语言中,也和C或者其他语言一样,我们可以声明新的类型,作为其它类型的属性或字段的容器。例如,我们可以创建一个自定义类型person代表一个人的...

35712
来自专栏Golang语言社区

Go语言struct类型详解

struct Go语言中,也和C或者其他语言一样,我们可以声明新的类型,作为其它类型的属性或字段的容器。例如,我们可以创建一个自定义类型person代表一个人的...

2967
来自专栏咸鱼不闲

jsoup爬虫工具的简单使用

解决方案: 1.通过url 获得doucment对象, 2.调用select()等方法获得Elements对象, 3.调用.text()等方法,获得自己想要的内...

4164
来自专栏Pythonista

golang之切片与排序

排序操作在sort包中,sort.Ints对整数进行排序,sort.Strings对字符串进行排序,sort.Float64对浮点数进行排序

732
来自专栏跟着阿笨一起玩NET

VB.NET自我总结语法

1091
来自专栏Golang语言社区

Go语言struct类型详解

struct Go语言中,也和C或者其他语言一样,我们可以声明新的类型,作为其它类型的属性或字段的容器。例如,我们可以创建一个自定义类型person代表一个人的...

2854
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础-day10-代码题-继承&抽象类

Java基础-day10-代码题-继承&抽象类 1.门类继承题: 编写代码,实现如下功能: (1)定义一个门类, 包含3个属性:宽度width 和 高度hei...

4726
来自专栏Golang语言社区

实效go编程--2

Go函数的返回值或结果“形参”可被命名,并作为常规变量使用,就像传入的形参一样。 命名后,一旦该函数开始执行,它们就会被初始化为与其类型相应的零值; 若该函数执...

3417

扫码关注云+社区

领取腾讯云代金券