社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
生命不止,继续 go go go !!!
reflect,即反射。对于C++程序员来说比较陌生,对于Java或是C#程序员来说理解反射就易如反掌了。
golang中为我们提供了reflect包用于反射,在这样跟诸位一起学习进步,只是浅尝辄止罢了。
反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
例如,
查看类的属性:
NewClassw nc = new NewClassw();
Type t = nc.GetType();
PropertyInfo[] pis = t.GetProperties();
foreach(PropertyInfo pi in pis)
{
Console.WriteLine(pi.Name);
}
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
例如,
通过一个对象,获得完整的包名和类名:
package net.xsoftlab.baike;
public class TestReflect {
public static void main(String[] args) throws Exception {
TestReflect testReflect = new TestReflect();
System.out.println(testReflect.getClass().getName());
}
}
再stackoverflow上有这样的问答,踏踏实实看看:
https://stackoverflow.com/questions/359237/why-does-c-not-have-reflection
接下来就要介绍golang中的reflect package了。
官方描述:
Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types. The typical use is to take a value with static type interface{} and extract its dynamic type information by calling TypeOf, which returns a Type.
reflect包有两个数据类型我们必须知道,一个是Type,一个是Value。
Type就是定义的类型的一个数据类型,Value是值的类型
反射是一种检查存储在接口变量中的<值,类型>对的机制,借助go反射包提供的reflect.TypeOf和reflect.ValueOf可以方便的访问到一个接口值的reflect.Type和reflect.Value部分,从而可进一步得到这个接口的结构类型和对其进行值的修改操作。
TypeOf() 获取到的结果是 reflect.Type 类型,ValueOf() 获取到的结果是 reflect.Value 类型,这两种类型都有很多方法可以进一步获取相关的反射信息。
首先是两个类型出场,value和type:
type Type interface {
// Align returns the alignment in bytes of a value of
// this type when allocated in memory.
Align() int
// FieldAlign returns the alignment in bytes of a value of
// this type when used as a field in a struct.
FieldAlign() int
// Method returns the i'th method in the type's method set.
// It panics if i is not in the range [0, NumMethod()).
//
// For a non-interface type T or *T, the returned Method's Type and Func
// fields describe a function whose first argument is the receiver.
//
// For an interface type, the returned Method's Type field gives the
// method signature, without a receiver, and the Func field is nil.
Method(int) Method
// MethodByName returns the method with that name in the type's
// method set and a boolean indicating if the method was found.
//
// For a non-interface type T or *T, the returned Method's Type and Func
// fields describe a function whose first argument is the receiver.
//
// For an interface type, the returned Method's Type field gives the
// method signature, without a receiver, and the Func field is nil.
MethodByName(string) (Method, bool)
// NumMethod returns the number of exported methods in the type's method set.
NumMethod() int
// Name returns the type's name within its package.
// It returns an empty string for unnamed types.
Name() string
// PkgPath returns a named type's package path, that is, the import path
// that uniquely identifies the package, such as "encoding/base64".
// If the type was predeclared (string, error) or unnamed (*T, struct{}, []int),
// the package path will be the empty string.
PkgPath() string
// Size returns the number of bytes needed to store
// a value of the given type; it is analogous to unsafe.Sizeof.
Size() uintptr
// String returns a string representation of the type.
// The string representation may use shortened package names
// (e.g., base64 instead of "encoding/base64") and is not
// guaranteed to be unique among types. To test for type identity,
// compare the Types directly.
String() string
// Kind returns the specific kind of this type.
Kind() Kind
// Implements reports whether the type implements the interface type u.
Implements(u Type) bool
// AssignableTo reports whether a value of the type is assignable to type u.
AssignableTo(u Type) bool
// ConvertibleTo reports whether a value of the type is convertible to type u.
ConvertibleTo(u Type) bool
// Comparable reports whether values of this type are comparable.
Comparable() bool
// Bits returns the size of the type in bits.
// It panics if the type's Kind is not one of the
// sized or unsized Int, Uint, Float, or Complex kinds.
Bits() int
// ChanDir returns a channel type's direction.
// It panics if the type's Kind is not Chan.
ChanDir() ChanDir
// IsVariadic reports whether a function type's final input parameter
// is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
// implicit actual type []T.
//
// For concreteness, if t represents func(x int, y ... float64), then
//
// t.NumIn() == 2
// t.In(0) is the reflect.Type for "int"
// t.In(1) is the reflect.Type for "[]float64"
// t.IsVariadic() == true
//
// IsVariadic panics if the type's Kind is not Func.
IsVariadic() bool
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
Elem() Type
// Field returns a struct type's i'th field.
// It panics if the type's Kind is not Struct.
// It panics if i is not in the range [0, NumField()).
Field(i int) StructField
// FieldByIndex returns the nested field corresponding
// to the index sequence. It is equivalent to calling Field
// successively for each index i.
// It panics if the type's Kind is not Struct.
FieldByIndex(index []int) StructField
// FieldByName returns the struct field with the given name
// and a boolean indicating if the field was found.
FieldByName(name string) (StructField, bool)
// FieldByNameFunc returns the struct field with a name
// that satisfies the match function and a boolean indicating if
// the field was found.
//
// FieldByNameFunc considers the fields in the struct itself
// and then the fields in any anonymous structs, in breadth first order,
// stopping at the shallowest nesting depth containing one or more
// fields satisfying the match function. If multiple fields at that depth
// satisfy the match function, they cancel each other
// and FieldByNameFunc returns no match.
// This behavior mirrors Go's handling of name lookup in
// structs containing anonymous fields.
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
// contains filtered or unexported methods
}
type Value struct {
// contains filtered or unexported fields
}
获取 t 类型的字符串描述,不要通过 String 来判断两种类型是否一致。
func (t *rtype) String() string
获取 t 类型在其包中定义的名称,未命名类型则返回空字符串。
func (t *rtype) Name() string
获取 t 类型所在包的名称,未命名类型则返回空字符串。
func (t *rtype) PkgPath() string
获取 t 类型的类别。
func (t *rtype) Kind() reflect.Kind
获取 t 类型的值在分配内存时的大小,功能和 unsafe.SizeOf 一样。
func (t *rtype) Size() uintptr
获取 t 类型的值在分配内存时的字节对齐值。
func (t *rtype) Align() int
获取 t 类型的值作为结构体字段时的字节对齐值。
func (t *rtype) FieldAlign() int
获取 t 类型的方法数量。
func (t *rtype) NumMethod() int
根据索引获取 t 类型的方法,如果方法不存在,则 panic。
如果 t 是一个实际的类型,则返回值的 Type 和 Func 字段会列出接收者。
如果 t 只是一个接口,则返回值的 Type 不列出接收者,Func 为空值。
func (t *rtype) Method() reflect.Method
根据名称获取 t 类型的方法。
func (t *rtype) MethodByName(string) (reflect.Method, bool)
判断 t 类型是否实现了 u 接口。
func (t *rtype) Implements(u reflect.Type) bool
判断 t 类型的值可否转换为 u 类型。
func (t *rtype) ConvertibleTo(u reflect.Type) bool
判断 t 类型的值可否赋值给 u 类型。
func (t *rtype) AssignableTo(u reflect.Type) bool
判断 t 类型的值可否进行比较操作
func (t *rtype) Comparable() bool
获取字段数量
func (t *rtype) NumField() int
根据索引获取字段
func (t *rtype) Field(int) reflect.StructField
根据名称获取字段
func (t *rtype) FieldByName(string) (reflect.StructField, bool)
根据指定的匹配函数 math 获取字段
func (t *rtype) FieldByNameFunc(match func(string) bool) (reflect.StructField, bool)
根据索引链获取嵌套字段
func (t *rtype) FieldByIndex(index []int) reflect.StructField
func ValueOf
func ValueOf(i interface{}) Value
ValueOf returns a new Value initialized to the concrete value stored in the interface i. ValueOf(nil) returns the zero Value.
获取对象类型和值
s := "i am string"
// 获取对象类型 (string)
fmt.Println(reflect.TypeOf(s))
// 获取对象值 (i am string)
fmt.Println(reflect.ValueOf(s))
var x float64 = 3.4
// 获取对象值 (<float64 Value>)
fmt.Println(reflect.ValueOf(x))
获取结构体的tag
package main
import (
"fmt"
"reflect"
)
type Test struct {
num int `gogo:"100"`
}
func main() {
test := new(Test)
test.num = 110
rcvr := reflect.ValueOf(test)
typ := reflect.Indirect(rcvr).Type()
fmt.Println(typ.Kind().String())
x := typ.NumField()
for i := 0; i < x; i++ {
nljb := typ.Field(0).Tag.Get("gogo")
fmt.Println(nljb)
}
}
通过反射修改对象
package main
import (
"fmt"
"reflect"
)
func main() {
y := 110
fmt.Println(y)
v := reflect.ValueOf(&y)
v.Elem().SetInt(119)
fmt.Println(y)
}
通过反射动态调用
package main
import (
"fmt"
"reflect"
)
type Person struct {
name string
age int
}
func Method(in interface{}) (ok bool) {
v := reflect.ValueOf(in)
if v.Kind() == reflect.Slice {
ok = true
} else {
//panic
}
num := v.Len()
for i := 0; i < num; i++ {
fmt.Println(v.Index(i).Interface())
}
return ok
}
func main() {
s := []int{1, 3, 5, 7, 9}
b := []float64{1.2, 3.4, 5.6, 7.8}
Method(s)
Method(b)
}
package main
import (
"fmt"
"reflect"
)
type Foo struct {
FirstName string `tag_name:"tag 1"`
LastName string `tag_name:"tag 2"`
Age int `tag_name:"tag 3"`
}
func (f *Foo) reflect() {
val := reflect.ValueOf(f).Elem()
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
tag := typeField.Tag
fmt.Printf("Field Name: %s,t Field Value: %v,t Tag Value: %sn", typeField.Name, valueField.Interface(), tag.Get("tag_name"))
}
}
func main() {
f := &Foo{
FirstName: "wang",
LastName: "shubo",
Age: 27,
}
f.reflect()
}
输出:
Field Name: FirstName, Field Value: wang, Tag Value: tag 1
Field Name: LastName, Field Value: shubo, Tag Value: tag 2
Field Name: Age, Field Value: 27, Tag Value: tag 3
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!