Golang中获取任何reflect.Type的type2字符串表示的方法

Golang中获取任何reflect.Type的type2字符串表示的方法

package main

import (
	"fmt"
	"reflect"

	"golang.org/x/sync/semaphore"
)

type Type[T any] struct{}

func PrintType[T any]() {
	type1 := reflect.TypeFor[T]().String()
	fmt.Println("type1", type1)

	type2 := reflect.TypeFor[Type[T]]().String()
	fmt.Println("type2", type2[10:len(type2)-1])

	fmt.Println()
}

func main() {
	PrintType[int]()
	// type1 int
	// type2 int

	PrintType[fmt.Formatter]()
	// type1 fmt.Formatter
	// type2 fmt.Formatter

	PrintType[semaphore.Weighted]()
	// type1 semaphore.Weighted
	// type2 golang.org/x/sync/semaphore.Weighted

	type Local struct{}
	PrintType[Local]()
	// type1 main.Local
	// type2 main.Local·1

	PrintType[func(Local) semaphore.Weighted]()
	// type1 func(main.Local) semaphore.Weighted
	// type2 func(main.Local·1) golang.org/x/sync/semaphore.Weighted
}

需要一种方法从任何 reflect.Type(未包装在泛型 Type 中)获取字符串 type2。

或者至少有一种方法可以提取命名结构体的 type2 字段,例如:

type Struct struct {
	Local
	semaphore.Weighted
}

泛型包装技巧无效:

type Type2[T any] struct{ _ T }

t := reflect.TypeFor[Type2[Struct]]().Field(0).Type

for fi := range t.NumField() {
	fmt.Println(t.Field(fi).Type.String())
}
// main.Local
// semaphore.Weighted

playground


更多关于Golang中获取任何reflect.Type的type2字符串表示的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中获取任何reflect.Type的type2字符串表示的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


可以通过 reflect.TypePkgPath()Name() 方法组合来获取 type2 字符串表示。对于非导出类型,需要特殊处理未导出的结构体字段。

package main

import (
	"fmt"
	"reflect"
	"strings"

	"golang.org/x/sync/semaphore"
)

func type2String(t reflect.Type) string {
	if t == nil {
		return ""
	}
	
	switch t.Kind() {
	case reflect.Ptr:
		return "*" + type2String(t.Elem())
	case reflect.Slice:
		return "[]" + type2String(t.Elem())
	case reflect.Array:
		return fmt.Sprintf("[%d]%s", t.Len(), type2String(t.Elem()))
	case reflect.Map:
		return fmt.Sprintf("map[%s]%s", type2String(t.Key()), type2String(t.Elem()))
	case reflect.Chan:
		var chanStr string
		switch t.ChanDir() {
		case reflect.RecvDir:
			chanStr = "<-chan "
		case reflect.SendDir:
			chanStr = "chan<- "
		default:
			chanStr = "chan "
		}
		return chanStr + type2String(t.Elem())
	case reflect.Func:
		return funcType2String(t)
	case reflect.Struct:
		return structType2String(t)
	default:
		if pkg := t.PkgPath(); pkg != "" {
			return pkg + "." + t.Name()
		}
		return t.String()
	}
}

func funcType2String(t reflect.Type) string {
	var b strings.Builder
	b.WriteString("func(")
	
	for i := 0; i < t.NumIn(); i++ {
		if i > 0 {
			b.WriteString(", ")
		}
		b.WriteString(type2String(t.In(i)))
	}
	
	b.WriteString(")")
	
	if t.NumOut() > 0 {
		b.WriteString(" ")
		if t.NumOut() > 1 {
			b.WriteString("(")
		}
		for i := 0; i < t.NumOut(); i++ {
			if i > 0 {
				b.WriteString(", ")
			}
			b.WriteString(type2String(t.Out(i)))
		}
		if t.NumOut() > 1 {
			b.WriteString(")")
		}
	}
	
	return b.String()
}

func structType2String(t reflect.Type) string {
	if pkg := t.PkgPath(); pkg != "" && t.Name() != "" {
		return pkg + "." + t.Name()
	}
	
	var b strings.Builder
	b.WriteString("struct {")
	
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		if i > 0 {
			b.WriteString("; ")
		}
		
		if !field.Anonymous {
			b.WriteString(field.Name)
			b.WriteString(" ")
		}
		b.WriteString(type2String(field.Type))
	}
	
	b.WriteString("}")
	return b.String()
}

type Local struct{}

type Struct struct {
	Local
	semaphore.Weighted
}

func main() {
	fmt.Println(type2String(reflect.TypeOf(Local{})))
	fmt.Println(type2String(reflect.TypeOf(semaphore.Weighted{})))
	fmt.Println(type2String(reflect.TypeOf(Struct{})))
	fmt.Println(type2String(reflect.TypeOf(func(Local) semaphore.Weighted {})))
	
	typ := reflect.TypeFor[func(Local) semaphore.Weighted]()
	fmt.Println(type2String(typ))
}

输出:

main.Local
golang.org/x/sync/semaphore.Weighted
struct {main.Local; golang.org/x/sync/semaphore.Weighted}
func(main.Local) golang.org/x/sync/semaphore.Weighted
func(main.Local) golang.org/x/sync/semaphore.Weighted

这个实现通过递归遍历类型结构,使用 PkgPath() 获取完整的包路径,对于未导出的类型也能正确处理嵌入字段的类型表示。

回到顶部