当前位置: 首页 > news >正文

go反射实战

文章目录

  • demo1 数据类型判断
  • demo2 打印任意类型数据

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}]

开始学起来吧

相关文章:

  • 微信小程序订阅消息授权弹窗事件
  • Python函数学习
  • 考研机试题
  • docker内部无法使用ping等网络工具解决方案
  • vscode中编写Markdown
  • 二叉树遍历(牛客网)
  • 项目中遇到的sql问题记录
  • 数据库增删改查复习
  • 如何将大华dav视频转mp4?一键无损清晰转换~
  • Layui实现删除及修改后停留在当前页
  • 将main打包成jar;idea打包main为jar包运行
  • 记录一下小程序自定义导航栏消息未读已读小红点,以及分组件的消息数量数据实时读取
  • 外包干了5天,技术明显退步。。。。。
  • 挑战杯 车位识别车道线检测 - python opencv
  • HTML_CSS练习:HTML注释
  • PostgreSQL中vacuum 物理文件truncate发生的条件
  • 高效使用git流程分享
  • 【数据结构与算法】:非递归实现快速排序、归并排序
  • 从零开始学HCIA之SDN04
  • 苍穹外卖-day08:导入地址簿功能代码(单表crud)、用户下单(业务逻辑)、订单支付(业务逻辑,cpolar软件)
  • 美国再工业化进程需要中国的产业支持
  • 人民日报刊文:加快解放和发展新质战斗力
  • 这座古村,藏着多少赣韵风华
  • 要更加冷静地看待“东升西降”的判断
  • 马上评丨维护学术诚信别陷入“唯AI检测”误区
  • 江西暴雨强对流明显,专家:落雨区高度重叠,地质灾害风险高