go反射实战

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

开始学起来吧

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值