go反射实战

文章目录

  • [demo1 数据类型判断](#demo1 数据类型判断)
  • [demo2 打印任意类型数据](#demo2 打印任意类型数据)

demo1 数据类型判断

  1. 使用reflect.TypeOf()方法打印go中数据类型,可参考go官方API文档;
  2. 使用格式化参数%T也能打印数据类型。
go 复制代码
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

    }

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

go 复制代码
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}]

开始学起来吧

相关推荐
llz_11227 分钟前
web-第二次课后作业
前端·后端·web
红尘散仙6 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记8 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
isyangli_blog8 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008118 小时前
FastAPI APIRouter
开发语言·python
Benszen8 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆8 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木8 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
喵个咪8 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
杨充9 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法