GO基础进阶篇 (十二)、反射

什么是反射

Go语言中的反射是指在程序运行时检查程序的结构,比如变量的类型、方法的签名等。Go语言的反射包是reflect。通过反射,你可以动态地检查类型信息、获取字段和方法、调用方法等。

反射可以在运行时动态获取变量的各种信息,比如变量的类型、值等
如果是结构体,还可以获取到结构体本身的各种信息,比如结构体的字段、方法
通过反射,还可以修改变量的值、调用方法
使用反射,需要引入一个包:reflect,它定义了内个重要的类型 Type 和 Value 任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value两部分组成,并且reflect 包提供了 reflect.Typ!alue和Type.Of和 reflect.ValueOf 两个函数来获取任意对象的 V
(Type)和种类(Kind)的区别。编程中,使用最多的是类型,但在反射中,当需要区分一个品种的类型时在使用反射时,需要首先理解类型.就会用到种类(Kind)。

package main

import (
	"fmt"
	"reflect"
)

func main() {
   
	var a float64 = 3.14
	fmt.Println(reflect.TypeOf(a))
	fmt.Println(reflect.ValueOf(a))

	v := reflect.ValueOf(a)

	if v.Kind() == reflect.Float64 {
   
		fmt.Println("v.kind() is float64")
	}

	fmt.Println(v.Type())
	fmt.Println(v.Float())
}

1.反射的应用场景

需要反射的2个常见场景:

  • 1.有时你需要编写一个函数,但是并不知道传给你的参数多型是什么,可能是没约定好;也可能是传入的类型很多,这时反射就会用的上了。
  • 2.有时候需要根据某些条件决定调用哪个函数,比如根据户的输入来决定。这时就需要对函数和函数的参数进行反函数。

但是对于反射,还是有几点不太建议使用反射的理由:

  • 1、与反射相关的代码,经常是难以阅读的。在软件工程中代码可读性也是一个非常重要的指标。
  • 2、Go语言作为一门静态语言,编码过程中,编译器能提发现一些类型错误,但是对于反射代码是无能为力的。所可能会运行很久,才会出错,这时候经常是直接panic,可会造成严重的后果。
  • 3、反射对性能影响还是比较大的,比正常代码运行速度慢一到两个数量级。所以,对于一个项目中处于运行效率关钱位置的代码,尽量避免使用反射特性。

2. 反射获取变量信息

package main

import (
	"fmt"
	"reflect"
)

type User struct {
   
	Name string
	Age  int
	Sex  string
}

func (user User) Say(msg string) {
   
	fmt.Println("user说", msg)
}
func main() {
   
	user := User{
   Name: "xiaolong", Age: 18, Sex: "男"}
	reflectGetInfo(user)
}

func reflectGetInfo(input interface{
   }) {
   

	//获取参数类型
	getType := reflect.TypeOf(input)
	fmt.Println("type is", getType.Name())
	fmt.Println("kind is", getType.Kind())

	//获取值
	getValue := reflect.ValueOf(input)
	fmt.Println("getValue is", getValue)

	
	//通过反射获取反射结果内的字段与方法
	for i := 0; i < getType.NumField(); i++ {
   
		filed := getType.Field(i)
		value := getValue.Field(i).Interface()
		fmt.Println(filed.Name, filed.Type, value)
	}

	for i := 0; i < getType.NumMethod(); i++ {
   
		method := getType.Method(i)
		fmt.Println(method.Name, method.Type)
	}
}

3.反射修改对象的值

package main

import (
	"fmt"
	"reflect"
)

func main() {
   
	var num float64 = 1.23

	point := reflect.ValueOf(&num) //想要通过指针修改值,需要传入指针
	newValue := point.Elem()
	fmt.Println(newValue.Kind())
	fmt.Println(newValue.Type())
	fmt.Println(newValue.CanSet())

	if newValue.CanSet() {
   
		newValue.SetFloat(3.14)
	}
	fmt.Println(num)
}

修改结构体

package main

import (
	"fmt"
	"reflect"
)

type User struct {
   
	Name string
	Age  int
	Sex  string
}

func (user User) Say(msg string) {
   
	fmt.Println("user说", msg)
}
func main() {
   
	user := User{
   Name: "xiaolong", Age: 18, Sex: "男"}
	fmt.Println(user)
	newValue := reflect.ValueOf(&user)

	if newValue.Kind() == reflect.Ptr {
    //首先是指针
		valueTemp := newValue.Elem()
		if valueTemp.CanSet() {
   
			valueTemp.FieldByName("Name").SetString("dalong")
			valueTemp.FieldByName("Age").SetInt(38)
		}
	}
	fmt.Println(user)
}

4.反射调用方法函数

方法调用

package main

import (
	"fmt"
	"reflect"
)

type User struct {
   
	Name string
	Age  int
	Sex  string
}

func (user User) Say(msg string) {
   
	fmt.Println("user说", msg)
}

func (user User) GetInfo() {
   
	fmt.Println("user 信息", user.Name, user.Age)
}

func main() {
   
	user := User{
   Name: "xiaolong", Age: 18, Sex: "男"}
	//reflectGetInfo(user)
	fmt.Println(user)

	//无参数方法调用
	value := reflect.ValueOf(user)
	value.MethodByName("GetInfo").Call(nil)

	//有参数方法调用
	args := make([]reflect.Value, 1)
	args[0] = reflect.ValueOf("反射调用")
	value.MethodByName("Say").Call(args)
}

函数调用

package main

import (
	"fmt"
	"reflect"
)

func main() {
   
	v1 := reflect.ValueOf(func1)
	v1.Call(nil)

	v2 := reflect.ValueOf(func2)
	args := make([]reflect.Value, 2)
	args[0] = reflect.ValueOf(1)
	args[1] = reflect.ValueOf("gagaga")
	v2.Call(args)

	v3 := reflect.ValueOf(func3)
	args1 := make([]reflect.Value, 2)
	args1[0] = reflect.ValueOf(1)
	args1[1] = reflect.ValueOf("gagaga")
	res := v3.Call(args1)
	fmt.Println(res[0].Interface())
}

func func1() {
   
	fmt.Println("无参数fun1")
}
func func2(i int, s string) {
   
	fmt.Println("有参数fun2", i, s)
}
func func3(i int, s string) string {
   
	fmt.Println("有参数fun3", i, s)
	return s
}

相关推荐

  1. GO基础 ()、反射

    2024-01-12 21:58:01       57 阅读
  2. GO基础 (三)、泛型

    2024-01-12 21:58:01       52 阅读
  3. Go语言系统学习笔记():

    2024-01-12 21:58:01       26 阅读
  4. GO基础 (八)、runtime包

    2024-01-12 21:58:01       66 阅读
  5. GO基础 (六)、I/O流

    2024-01-12 21:58:01       52 阅读
  6. go语言——接口

    2024-01-12 21:58:01       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-12 21:58:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-12 21:58:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-12 21:58:01       82 阅读
  4. Python语言-面向对象

    2024-01-12 21:58:01       91 阅读

热门阅读

  1. 如何一键合并多个excel文件

    2024-01-12 21:58:01       54 阅读
  2. [linux] git clone一个repo,包括它的子模块submodule

    2024-01-12 21:58:01       61 阅读
  3. 用PYTHON学算法DAY1--位运算相关

    2024-01-12 21:58:01       54 阅读
  4. QT day5

    QT day5

    2024-01-12 21:58:01      55 阅读
  5. 用python实现把PDF转成图片,测试成功转化代码

    2024-01-12 21:58:01       43 阅读
  6. __declspec(dllexport)与__declspec(dllimport) 的区别

    2024-01-12 21:58:01       45 阅读
  7. C语言学习记录—进阶作业(通讯录静态版本)

    2024-01-12 21:58:01       54 阅读