理解反射之:一个reflect.Type可以做什么

反射是一个接口,其定义如下: type Type interface { // 返回具体类型在内存分配时的字节分配方式 Align() int // 返回具体类型在结构体中作为一个字段是内存对齐方式 FieldAlign() int // 返回具体类型的第x个方法 Method(int) Method // 根据函数名返回具体类型的方法 MethodByName(string) (Method, bool) // 返回类型的方法个数 NumMethod() int // 返回类型的名字 Name() string // 返回类型的包名 PkgPath() string // 返回类型所占内存字节大小 Size() uintptr // 返回类型的简单描述,如:main.User String() string // 返回这个类型的Kind Kind() Kind // 检查类型是否实现了某个接口 //stringer := reflect.TypeOf((*fmt.Stringer)(nil)).Elem() //fmt.Println(reflect.ValueOf(u).Type().Implements(stringer)) Implements(u Type) bool // 检查类型是否可以被赋值给某个类型 AssignableTo(u Type) bool // 检查类型是否可以转换到类型u ConvertibleTo(u Type) bool // 检查类型是否可比较 Comparable() bool // 返回Int, Uint, Float, or Complex kinds....

March 15, 2022 · 1 min · 李昌

golang中的tag

1. tag的基本介绍 字段标签可以存储元信息,这些元信息可以使用反射来访问。通常这些元信息用来提供一个字段如何从一种格式编码至另一种格式的相关信息(或是数据应如何在数据库中存储等)。但实际上标签可以存储任何你想要的元信息,无论是你自己使用还是由另一个包使用。 就像reflect.StructTag文档中提到的那样,字段标签通常是由空格分割的key:"value"列表,例如: type User struct { Name string `json:"name" xml:"name"` } 其中的key通常表示后面"value"所对应的包,例如json这个key将被encoding/json这个包使用。 如果需要在"value"中传递多个值,那么通常使用,逗号来分割,例如: Name string `json:"name,omitempty" xml:"name"` 值为破折号通常代表在处理时忽略该字段,例如在json中代表不要序列化这个字段 2. 例子:获取自定义tag 我们可以使用反射包来获取结构体字段的值。首先我们需要获取结构体的Type,然后查询字段,可以使用Type.Field(i int)或者Type.FieldByName(name string)。这些方法返回一个代表结构体字段的StructField值和一个代表tag的类型为StructTag的StructField.Tag值。 前面我们提到,字段标签通常是由空格分割的key:"value"列表,如果你的确是这么做的,你可以使用StructTag.Get(key string)这个方法来获取这个key对应的value。如果你不是这么做的,Get()方法可能不能解析key:"value"对并找到你想要的标签。如果你没有遵循字段标签通常是由空格分割的key:"value"列表,那么你可能需要实现自己的解析逻辑。 go1.7中添加了StructTag.Lookup()方法,这个方法的行为类似于Get(),但其将不包含给定键的标签与将空字符串与给定键相关联的标签区分开来。 来看下面这个例子: type User struct { Name string `mytag:"MyName"` Email stirng `mytag:"MyEmail"` } u := User{"Bob", "bob@cc.com"} t := reflect.TypeOf(u) for _ fieldName := range []string{"Name", "Email"} { field, found := t.FieldByName(fieldName) if !found { continue } fmt.Printf("\nField: User.%s\n", fieldName) fmt.Printf("\tWhole tag value : %q\n", field....

September 14, 2021 · 2 min · 李昌

Golang中反射reflect的基本使用

在计算机领域,反射是指一类应用,它们能够自描述和自控制。也即是说,这类应用通过采用某种机制来实现对自己行为的描述和监测,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。 反射(reflect)让我们能在运行期探知对象的类型信息和内存结构,这从一定程度上弥(mi)补了静态语言在动态行为上的不足。 反射(reflect)是在计算机程序运行时,访问,检查,修改它自身的一种能力,是元编程的一种形式。 Go语音提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法和它们支持的内在操作,但是在编译时并不知道这些变量的具体类型。这种机制被称为反射。反射也可以让我们将类型本身作为第一类的值类型处理。 1. 为何我们需要反射? fmt.Fprintf函数提供字符串格式化处理逻辑,它可以对任意类型的值格式化并打印,甚至支持用户自定义的类型。 让我们也来尝试实现一个类似功能的函数。为了简单起见,我们的函数只接收一个参数,然后返回和fmt.Sprint类似的格式化后的字符串。我们实现的函数名也叫Sprint。 这里我们使用switch类型分支来对不同的类型进行处理。 func Sprint(x interface{}) string { type stringer interface { String() string } switch x := x.(type) { case stringer: return x.String() case string: return x case int: return strconv.Itoa(x) // ...similar cases for int16, uint32, and so on... case bool: if x { return "true" } return "false" default: // array, chan, func, map, pointer, slice, struct return "?...

May 22, 2021 · 4 min · 李昌