Go语言学习之reflect包(The way to go) - Go语言中文社区

Go语言学习之reflect包(The way to go)


生命不止,继续 go go go !!!

reflect,即反射。对于C++程序员来说比较陌生,对于Java或是C#程序员来说理解反射就易如反掌了。

golang中为我们提供了reflect包用于反射,在这样跟诸位一起学习进步,只是浅尝辄止罢了。

C#中反射

反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

例如,
查看类的属性:

    NewClassw nc = new NewClassw();
    Type t = nc.GetType();
    PropertyInfo[] pis = t.GetProperties();
    foreach(PropertyInfo pi in pis)
    {
        Console.WriteLine(pi.Name);
    }

Java中反射

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());
    }
}

为什么C++中没有反射

再stackoverflow上有这样的问答,踏踏实实看看:
https://stackoverflow.com/questions/359237/why-does-c-not-have-reflection

package reflect

接下来就要介绍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
这里写图片描述

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/wangshubo1989/article/details/75308222
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 15:32:28
  • 阅读 ( 1038 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢