【go源码分析】go源码之反射reflect源码分析

1. 反射描述

      反射是指能够自描述和自控制,通过采用某种机制来实现对自己行为的描述。Golang语言实现了反射,反射机制就是在运行时动态的调用对象的方法和属性,官方自带的reflect包就是反射相关的

      Golang设计的原则中变量包括(type, value)两部分,反射主要与Golang的interface类型相关,只有interface类型才有反射机制,实现路径为src/reflect文件中

 

  1.1 静态类型

        静态类型语言。每个变量的类型在编译时都是确定的:int,float32, *AutoType, []byte,

  1.2 动态 类型

       动态类型:运行时给这个变量复制(如果值为nil的时候没有动态类型)。一个变量的动态类型在运行时可能改变,这主要依赖于它的赋值(前提是这个变量时接口类型)

 

2. 接口

  2.1 Type接口

  • Name: 返回类型的名称。 没有类型名称返回空字符串
  • Kind: 返回type类型,如2.2所示
  • Elem: 如果不是Array, Chan, Map, Ptr, or Slice将产生panic
  • Field: 返回第i个字段,只能使用在struct类型,其他类型或者跃界将panic
  • Key: 返回map类型的key类型,非map类型将panic
  • Len: 返回数组的长度,其他类型将panic
type Type interface {
        // Methods applicable to all types.
        
        // 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
        Name() string
        Kind() Kind
        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

        // 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

  2.2 Kind类型

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   
        Ptr   
        Slice 
        String
        Struct
        UnsafePointer
) 

  2.3 emptyInterface结构体

// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
        typ  *rtype
        word unsafe.Pointer
}

 

3. Type

  3.1 TypeOf函数

    动态获取输入参数接口中的值的类型,如果接口为空则返回nil

    转换为emptyInterface

// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i interface{}) Type {
        eface := *(*emptyInterface)(unsafe.Pointer(&i))
        return toType(eface.typ)
}

  3.2 rtype结构体,实现了Type接口

  • size: 存储这个类型的一个值所需要的字节数(值占用的字节数)
  • algin: 这个类型的一个变量在内存中的对齐后的所用的字节数 (变量占的字节数)
  • FieldAlign: 这种类型的变量如果是struct中的字段,那么它对齐后所用的字节数
// rtype is the common implementation of most values.
// It is embedded in other struct types.
//              
// rtype must be kept in sync with ../runtime/type.go:/^type._type.
type rtype struct { 
        size       uintptr
        ptrdata    uintptr  // number of bytes in the type that can contain pointers
        hash       uint32   // hash of type; avoids computation in hash tables
        tflag      tflag    // extra type information flags
        align      uint8    // alignment of variable with this type
        fieldAlign uint8    // alignment of struct field with this type
        kind       uint8    // enumeration for C
        alg        *typeAlg // algorithm table
        gcdata     *byte    // garbage collection data
        str        nameOff  // string form
        ptrToThis  typeOff  // type for pointer to this type, may be zero
} 

 

4. Value

    Value描述对象的值信息,并不是所有的方法对任何的类型都有意义,特定的方法只适用于特定的类型

type Value struct {
        // typ holds the type of the value represented by a Value.
        typ *rtype
       
        // Pointer-valued data or, if flagIndir is set, pointer to data.
        // Valid when either flagIndir is set or typ.pointers() is true.
        ptr unsafe.Pointer
       
        // flag holds metadata about the value.
        // The lowest bits are flag bits:
        //      - flagStickyRO: obtained via unexported not embedded field, so read-only
        //      - flagEmbedRO: obtained via unexported embedded field, so read-only
        //      - flagIndir: val holds a pointer to the data
        //      - flagAddr: v.CanAddr is true (implies flagIndir)
        //      - flagMethod: v is a method value.
        // The next five bits give the Kind of the value.
        // This repeats typ.Kind() except for method values.
        // The remaining 23+ bits give a method number for method values.
        // If flag.kind() != Func, code can assume that flagMethod is unset.
        // If ifaceIndir(typ), code can assume that flagIndir is set.
        flag
       
        // A method value represents a curried method invocation
        // like r.Read for some receiver r. The typ+val+flag bits describe
        // the receiver r, but the flag's Kind bits say Func (methods are
        // functions), and the top bits of the flag give the method number
        // in r's type's method table.
}

 

总结

   Golang reflect慢主要有两个原因

  • 涉及到内存分配以及后续的GC
  • reflect实现里面有大量的枚举,也就是for循环,比如类型之类的

 

示例

package main

import (
	"fmt"
	"reflect"
)

type Bird struct {
	name     string
	age      int
	location string
}

func (b Bird) Sing() string {
	return "sing func"
}

func (b *Bird) Fly() string {
	return "fly func"
}

func (b *Bird) Eat() {
}

func main() {
	bird := Bird{
		name:     "pig",
		age:      100,
		location: "Beijing",
	}

	t := reflect.TypeOf(bird)

	fmt.Printf("type t = %#v\n", t)

	fmt.Printf("type name = %#v\n", t.Name())
	fmt.Printf("type string = %#v\n", t.String())
	fmt.Printf("type pkg path = %#v\n", t.PkgPath())
	fmt.Printf("type kind = %#v\n", t.Kind())
	fmt.Printf("type size = %#v\n", t.Size())

	fieldType, _ := t.FieldByName("age")
	fmt.Printf("type field: %v", fieldType)

	v := reflect.ValueOf(bird)

	fmt.Printf("value of: %#v\n", v)
	fmt.Printf("value of Type: %#v\n", v.Type())
	fmt.Printf("value of Type name: %#v\n", v.Type().Name())
	fmt.Printf("value of Type size: %#v\n", v.Type().Size())
	fmt.Printf("value of Type kind: %#v\n", v.Type().Kind())

	fieldValue := v.FieldByName("age")

	fmt.Printf("value field age  = %#v", fieldValue)
}

 

你可能感兴趣的:(编程语言)