首页 > 其他分享 >go反射实战

go反射实战

时间:2024-03-14 19:34:19浏览次数:27  
标签:实战 反射 int fmt reflect 类型 AnyToString go type

文章目录

demo1 数据类型判断

  1. 使用reflect.TypeOf()方法打印go中数据类型,可参考go官方API文档;
  2. 使用格式化参数%T也能打印数据类型。
package main

import "fmt"
import "reflect"
import "io"
import "os"

func main() {
	TypeTest()
}

func TypeTest() {
	tInt := reflect.TypeOf(3)               // int
	tStr := reflect.TypeOf("文字")           // string
	tBool := reflect.TypeOf(true)            // bool
	tFloat := reflect.TypeOf(3.14)           // float64
	tSlice := reflect.TypeOf([]int{1, 2})    // []int
	tMap := reflect.TypeOf(map[int]string{}) // map[int]string
	var w io.Writer = os.Stdout              // *os.File
	tW := reflect.TypeOf(w)
	fmt.Println(tInt, tStr, tBool, tFloat, tSlice, tMap, tW)
	fmt.Printf("%T %T %T %T %T %T %T", 3, "feng", true, 3.14, []int{1, 2}, map[int]string{}, os.Stdout)
}

输出

int string bool float64 []int map[int]string *os.File
int string bool float64 []int map[int]string *os.File

demo2 打印任意类型数据

开始写代码之前,简单了解一些reflect包中的结构体和方法。

1.结构体:reflect.Value(类型+数据指针)

type Value struct {
	typ *rtype
	ptr unsafe.Pointer
	flag
}
type flag uintptr

2.方法:reflect.ValueOf()
入参:接口interface{},也就是任意类型
出参:reflect.Value结构体

func ValueOf(i any) Value {
	if i == nil {
		return Value{}
	}
	escapes(i)
	return unpackEface(i)
}

3.方法:reflect.Value{}.Interface()
将Value的数据值转为interface{}类型

func (v Value) Interface() (i any) {
	return valueInterface(v, true)
}

4.类型:reflect.Kind
实际上Kind是一个uint类型的别名,使用Kind类型定义了go中各种数据类型,枚举如下
(iota变量是0,常量块定义中使用iota,后面的如果没有指定数值,一般就是自增)

type Kind uint

const (
	Invalid Kind = iota
	Bool
	Int
	Int8
	Int16
	Int32
	Int64
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Uintptr
	Float32
	Float64
	Complex64
	Complex128
	Array
	Chan
	Func
	Interface
	Map
	Pointer
	Slice
	String
	Struct
	UnsafePointer
)
  1. 结构体:reflect.Type(数据类型)
type Type interface {
	// 对齐方式
	Align() int
	
	// 结构体字段的对齐方式
	FieldAlign() int
	
	// 从方法集合中返回索引为i的方法
	Method(int) Method
	
    // 通过方法名在方法集合中找方法,返回方法和是否找到的bool类型结果
	MethodByName(string) (Method, bool)
	
	// 返回方法数量
	NumMethod() int

	// 返回类型的名称,例如 int、string等
	Name() string

	//  返回包路径,例如"encoding/base64"
	PkgPath() string

	// 返回类型大小,比如int占8字节
	Size() uintptr
	
	// 返回最段的类型,例如”base64“而不是"encoding/base64"
	String() string

	// 返回类型的数字枚举
	Kind() Kind
	
	// 返回u类型是否实现了接口
	Implements(u Type) bool

	// 当前类型的值是否可以赋值为u类型
	AssignableTo(u Type) bool

	// 当前类型的值是否可以转换为u类型,就算可转换,依然可能会panic。比如数组大小不匹配时进行转换
	ConvertibleTo(u Type) bool

	// 此类型是否可比较,返回true在比较时也可能panic,因为interface是可比较的,但是interface的子类可能是不可比较的
	Comparable() bool

	Bits() int

	ChanDir() ChanDir

	IsVariadic() bool

	// 返回此类型的元素类型,必须是Array、Chan、Map、Pointer、Slice类型调用,否则会panic
	Elem() Type

	// 返回索引为i的结构体类型的字段
	Field(i int) StructField

	// 必须是结构体调用,否则会panic。返回嵌套字段
	FieldByIndex(index []int) StructField

	// 根据名字获取字段,找到返回true
	FieldByName(name string) (StructField, bool)

	// 根据条件查找字段
	FieldByNameFunc(match func(string) bool) (StructField, bool)

	// In returns the type of a function type's i'th input parameter.
	// It panics if the type's Kind is not Func.
	// It panics if i is not in the range [0, NumIn()).
	In(i int) Type

	// Key returns a map type's key type.
	// It panics if the type's Kind is not Map.
	Key() Type

	// Len returns an array type's length.
	// It panics if the type's Kind is not Array.
	Len() int

	// NumField returns a struct type's field count.
	// It panics if the type's Kind is not Struct.
	NumField() int

	// NumIn returns a function type's input parameter count.
	// It panics if the type's Kind is not Func.
	NumIn() int

	// NumOut returns a function type's output parameter count.
	// It panics if the type's Kind is not Func.
	NumOut() int

	// Out returns the type of a function type's i'th output parameter.
	// It panics if the type's Kind is not Func.
	// It panics if i is not in the range [0, NumOut()).
	Out(i int) Type

	common() *rtype
	uncommon() *uncommonType
}

了解反射包下的基本数据结构和方法后,下面开始编程

package main

import (
	"fmt"
	"reflect"
	"strconv"
)

// 任何类型转打印
func AnyToString(a interface{}) string {
	// v是Value类型,属性包含a的实际类型+值
	v := reflect.ValueOf(a)
	// 判断v的类型
	switch v.Kind() {
	case reflect.Invalid: // 无效值
		return "invalid"
	case reflect.String: // 字符串
		return v.String()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: // 数字类型
		return strconv.FormatInt(v.Int(), 10)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: // 无符号数字类型
		return strconv.FormatUint(v.Uint(), 10)
	case reflect.Bool: // 布尔类型
		return strconv.FormatBool(v.Bool())
	case reflect.Float64, reflect.Float32: // 浮点数类型
		return strconv.FormatFloat(v.Float(), 'f', -1, 64)
	case reflect.Ptr: // 指针类型
		if v.IsNil() {
			return "<nil>"
		}
		// v.Elem()取出指针指向的数据,类型为reflect.Value
		// v.Elem().Interface()将reflect.Value转为interface{}
		// AnyToString(v.Elem().Interface()) 递归再次获取字符串
		return AnyToString(v.Elem().Interface())
	case reflect.Slice, reflect.Array: // 切片和数组类型
		s := "["
		// 获取数组或者切片的长度
		length := v.Len()
		for i := 0; i < length; i++ {
			// v.Index(i)为获取下标为i的reflect.Value类型数据
			// v.Index(i).Interface() 将reflect.Value转为interface{}
			// AnyToString(v.Index(i).Interface()) 递归再次获取字符串
			s += AnyToString(v.Index(i).Interface())
			if i < length-1 {
				s += ","
			}
		}

		s += "]"
		return s
	case reflect.Map: // 字典类型
		// 反射获取map的所有key
		keys := v.MapKeys()
		// 获取map的长度
		length := len(keys)
		s := "{"
		for i := 0; i < length; i++ {
			key := keys[i]
			// 获取map的value
			value := v.MapIndex(key)
			s += fmt.Sprintf("%s", AnyToString(key.Interface())) // 拼接key
			s += ": "
			s += AnyToString(value.Interface()) // 拼接value
			if i < length-1 {
				s += ", "
			}
		}
		s += "}"
		return s
	case reflect.Struct: // 结构体类型
		s := "{"
		count := v.NumField() // 获取结构体的字段数量
		for i := 0; i < count; i++ {
			// v.Type().Field(i) 
			s += fmt.Sprintf("%s:%s", v.Type().Field(i).Name, AnyToString(v.Field(i).Interface()))
			if i < count-1 {
				s += ","
			}
		}
		s += "}"
		return s
	default: // 其他类型
		return fmt.Sprintf("%+v", v)
	}
}

func main() {
	fmt.Println(AnyToString(1))
	fmt.Println(AnyToString("字符串"))
	fmt.Println(AnyToString(3.1415926))
	fmt.Println(AnyToString(255))
	fmt.Println(AnyToString([]int{1, 2, 3}))
	fmt.Println(AnyToString(map[string]int{"age": 1}))

	account := &Account{
		Age:  2,
		Name: "jinnian",
	}
	accountList := []Account{
		{1, "wo"},
		{0, "c"},
	}
	fmt.Println(AnyToString(accountList))
	fmt.Println(AnyToString(account))
	fmt.Println(AnyToString(nil))
	fmt.Println(AnyToString(true))
	fmt.Println(AnyToString(&accountList))
}

输出

1
字符串
3.1415926
255
[1,2,3]
{age: 1}
[{Age:1,Name:wo},{Age:0,Name:c}]
{Age:2,Name:jinnian}
invalid
true
[{Age:1,Name:wo},{Age:0,Name:c}]

开始学起来吧

标签:实战,反射,int,fmt,reflect,类型,AnyToString,go,type
From: https://blog.csdn.net/weixin_43093878/article/details/136716307

相关文章

  • Go语言中的面向对象编程(OOP)
    在Go语言中,虽然没有像面向对象语言那样的类,但通过结构体类型和方法,仍然支持部分面向对象编程(OOP)的概念。封装(Encapsulation)封装是一种将一个对象的实现细节隐藏起来,使其对其他对象不可见的做法,这样可以实现解耦。例如,考虑以下结构体:typeStudentstruct{namestring......
  • Kubernetes operator(十) kubebuilder 实战演练 之 开发多版本CronJob【更新中】
    云原生学习路线导航页(持续更新中)本文是Kubernetesoperator学习系列第十篇,本节会在前篇开发的Cronjob基础上,进行多版本Operator开发的实战本文的所有代码,都存储于github代码库:https://github.com/graham924/share-code-operator-study/tree/main/cronJob-operato......
  • gorm使用事务并发情况下切有最大mysql连接数限制的情况下的BUG,踩坑了
    现象服务器pprof中的goroutines很多,无法释放,肯定是异常.代码//收到请求上个赛季个人秘境赛季排行func(this*MsgProc)MsgProc_PersonSecretLastRankReq(msg*protoMsg.PersonSecretLastRankReq){ global.GetSrvInst().GetThreadGo().Go(func(ctxcontext.Context)......
  • 操作Redis之go-redis
    目录一、go操作redis的选择二、redis安装1.windowd平台安装方案2.mac平台和linux平台安装方案3.redis应用三、快速使用1.快速连接2.字符串操作(1)方法(2)示例3.列表操作(1)方法(2)示例4.hash操作(1)方法(2)示例5.集合操作(1)方法(2)示例6.有序集合操作(1)方法(2)示例7.通用操作(1)方法(2)示例8.......
  • 操作Redis之redigo
    目录一、go操作redis的选择二、redigo快速使用1.快速链接三、redis操作四、连接池一、go操作redis的选择golang操作redis主要有两个库,go-redis和redigo。go-redis:star数更多,支持连接哨兵及集群模式的Redisredigo:star数少一些,操作更简单二、redigo快速使用安装:gog......
  • RAG实战6-如何在LlamaIndex中使用自己搭建的API
    RAG实战6-如何在LlamaIndex使用自己搭建的大模型API在搭建一个大模型API服务中,我们介绍了如何使用SWIFT框架搭建一个大模型API服务。在RAG实战1-5中,我们一直使用的是本地加载大模型的方式来调用大模型,本文将介绍如何在LlamaIndex中使用自己搭建的大模型API。LlamaIndex支持部分......
  • C++、Java 和 Go 是三种流行的编程语言,它们各有不同的特点和应用场景
    C++:面向对象和泛型编程:C++是一种多范式编程语言,支持面向对象编程(OOP)和泛型编程(GenericProgramming)。性能:C++是一种系统级编程语言,注重性能和内存管理。它提供了直接的内存访问和指针操作,使得程序员可以更精细地控制内存和计算资源。灵活性:C++允许程序员直接操作硬件,并提......
  • Python实现BOA蝴蝶优化算法优化循环神经网络分类模型(LSTM分类算法)项目实战
    说明:这是一个机器学习实战项目(附带数据+代码+文档+视频讲解),如需数据+代码+文档+视频讲解可以直接到文章最后获取。1.项目背景蝴蝶优化算法(butterflyoptimizationalgorithm,BOA)是Arora等人于2019年提出的一种元启发式智能算法。该算法受到了蝴蝶觅食和交配行为的启发,......
  • Python实现BOA蝴蝶优化算法优化循环神经网络回归模型(LSTM回归算法)项目实战
    说明:这是一个机器学习实战项目(附带数据+代码+文档+视频讲解),如需数据+代码+文档+视频讲解可以直接到文章最后获取。1.项目背景蝴蝶优化算法(butterflyoptimizationalgorithm,BOA)是Arora等人于2019年提出的一种元启发式智能算法。该算法受到了蝴蝶觅食和交配行为的启发,......
  • 极狐GitLab和企业微信的集成实战
    企业微信是国内企业使用较多的即时通信工具,极狐GitLab自16.2就和企业微信做了集成,极狐GitLab相关的变更都可以直接发送到对应的企业微信群,然后开发人员去处理。仅需两步即可完成极狐GitLab和企业微信的集成。前提由于该功能使用FeatureFlagwecom_integration控制,当......