当前位置:   article > 正文

go反射实战

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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

输出

int string bool float64 []int map[int]string *os.File
int string bool float64 []int map[int]string *os.File
  • 1
  • 2

demo2 打印任意类型数据

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

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

type Value struct {
	typ *rtype
	ptr unsafe.Pointer
	flag
}
type flag uintptr
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

func ValueOf(i any) Value {
	if i == nil {
		return Value{}
	}
	escapes(i)
	return unpackEface(i)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

func (v Value) Interface() (i any) {
	return valueInterface(v, true)
}
  • 1
  • 2
  • 3

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

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

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108

输出

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}]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

开始学起来吧

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/247810
推荐阅读
相关标签
  

闽ICP备14008679号