【go原始碼分析】go原始碼之反射reflect原始碼分析
阿新 • • 發佈:2019-01-05
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)
}