------------------------------------------------------------ 在 reflect 包中,主要經過兩個函數 TypeOf() 和 ValueOf() 實現反射,TypeOf() 獲取到的結果是 reflect.Type 類型,ValueOf() 獲取到的結果是 reflect.Value 類型,這兩種類型都有不少方法能夠進一步獲取相關的反射信息。 這裏有一個函數,能夠獲取指定對象的全部字段和方法: ------------------------------ // 獲取一個對象的字段和方法 package main import ( "fmt" "reflect" ) // 獲取一個對象的字段和方法 func GetMembers(i interface{}) { // 獲取 i 的類型信息 t := reflect.TypeOf(i) for { // 進一步獲取 i 的類別信息 if t.Kind() == reflect.Struct { // 只有結構體能夠獲取其字段信息 fmt.Printf("\n%-8v %v 個字段:\n", t, t.NumField()) // 進一步獲取 i 的字段信息 for i := 0; i < t.NumField(); i++ { fmt.Println(t.Field(i).Name) } } // 任何類型均可以獲取其方法信息 fmt.Printf("\n%-8v %v 個方法:\n", t, t.NumMethod()) // 進一步獲取 i 的方法信息 for i := 0; i < t.NumMethod(); i++ { fmt.Println(t.Method(i).Name) } if t.Kind() == reflect.Ptr { // 若是是指針,則獲取其所指向的元素 t = t.Elem() } else { // 不然上面已經處理過了,直接退出循環 break } } } // 定義一個結構體用來進行測試 type sr struct { string } // 接收器爲實際類型 func (s sr) Read() { } // 接收器爲指針類型 func (s *sr) Write() { } func main() { // 測試 GetMembers(&sr{}) } /* 測試結果(能夠讀取私有字段): *main.sr 2 個方法: Read Write main.sr 1 個字段: string main.sr 1 個方法: Read */ ------------------------------ 咱們能夠經過下面的代碼獲取 reflect.Type 的全部方法,以便進行學習: // reflect.Type 是一個接口類型 GetMembers(new(reflect.Type)) 列出的方法並不必定通用,須要根據不一樣的類型選擇使用,咱們在這裏給它們分一下類: ------------------------------ // 通用 // 獲取 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 ------------------------------ // 示例 type inf interface { Method1() Method2() } type ss struct { a func() } func (i ss) Method1() {} func (i ss) Method2() {} func main() { s := reflect.TypeOf(ss{}) i := reflect.TypeOf(new(inf)).Elem() Test(s) Test(i) } func Test(t reflect.Type) { if t.NumMethod() > 0 { fmt.Printf("\n--- %s ---\n", t) fmt.Println(t.Method(0).Type) fmt.Println(t.Method(0).Func.String()) } } // 輸出結果: // --- main.ss --- // func(main.ss) // <func(main.ss) Value> // // --- main.inf --- // func() // <invalid Value> ------------------------------ // 數值 // 獲取數值類型的位寬,t 必須是整型、浮點型、複數型 func (t *rtype) Bits() int ------------------------------ // 數組 // 獲取數組的元素個數 func (t *rtype) Len() int ------------------------------ // 映射 // 獲取映射的鍵類型 func (t *rtype) Key() reflect.Type ------------------------------ // 通道 // 獲取通道的方向 func (t *rtype) ChanDir() reflect.ChanDir ------------------------------ // 結構體 // 獲取字段數量 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 (t *rtype) NumIn() int // 根據索引獲取函數的參數信息 func (t *rtype) In(int) reflect.Type // 獲取函數的返回值數量 func (t *rtype) NumOut() int // 根據索引獲取函數的返回值信息 func (t *rtype) Out(int) reflect.Type // 判斷函數是否具備可變參數。 // 若是有可變參數,則 t.In(t.NumIn()-1) 將返回一個切片。 func (t *rtype) IsVariadic() bool ------------------------------ // 數組、切片、映射、通道、指針、接口 // 獲取元素類型、獲取指針所指對象類型,獲取接口的動態類型 func (t *rtype) Elem() reflect.Type ------------------------------ 下面的代碼用到了全部這些方法: ------------------------------ // 獲取各類類型的相關信息 package main import ( "fmt" "reflect" "unsafe" ) // 嵌套結構體 type ss struct { a struct { int string } int string bool float64 } func (s ss) Method1(i int) string { return "結構體方法1" } func (s *ss) Method2(i int) string { return "結構體方法2" } var ( intValue = int(0) int8Value = int8(8) int16Value = int16(16) int32Value = int32(32) int64Value = int64(64) uIntValue = uint(0) uInt8Value = uint8(8) uInt16Value = uint16(16) uInt32Value = uint32(32) uInt64Value = uint64(64) byteValue = byte(0) runeValue = rune(0) uintptrValue = uintptr(0) boolValue = false stringValue = "" float32Value = float32(32) float64Value = float64(64) complex64Value = complex64(64) complex128Value = complex128(128) arrayValue = [5]string{} // 數組 sliceValue = []byte{0, 0, 0, 0, 0} // 切片 mapValue = map[string]int{} // 映射 chanValue = make(chan int, 2) // 通道 structValue = ss{ // 結構體 struct { int string }{10, "子結構體"}, 20, "結構體", false, 64.0, } func1Value = func(a, b, c int) string { // 函數(固定參數) return fmt.Sprintf("固定參數:%v %v %v", a, b, c) } func2Value = func(a, b int, c ...int) string { // 函數(動態參數) return fmt.Sprintf("動態參數:%v %v %v", a, b, c) } unsafePointer = unsafe.Pointer(&structValue) // 通用指針 reflectType = reflect.TypeOf(0) // 反射類型 reflectValue = reflect.ValueOf(0) // 反射值 reflectArrayValue = reflect.ValueOf([]int{1, 2, 3}) // 切片反射值 // 反射接口類型 interfaceType = reflect.TypeOf(new(interface{})).Elem() ) // 簡單類型 var simpleTypes = []interface{}{ intValue, &intValue, // int int8Value, &int8Value, // int8 int16Value, &int16Value, // int16 int32Value, &int32Value, // int32 int64Value, &int64Value, // int64 uIntValue, &uIntValue, // uint uInt8Value, &uInt8Value, // uint8 uInt16Value, &uInt16Value, // uint16 uInt32Value, &uInt32Value, // uint32 uInt64Value, &uInt64Value, // uint64 byteValue, &byteValue, // byte runeValue, &runeValue, // rune uintptrValue, &uintptrValue, // uintptr boolValue, &boolValue, // bool stringValue, &stringValue, // string float32Value, &float32Value, // float32 float64Value, &float64Value, // float64 complex64Value, &complex64Value, // complex64 complex128Value, &complex128Value, // complex128 } // 複雜類型 var complexTypes = []interface{}{ arrayValue, &arrayValue, // 數組 sliceValue, &sliceValue, // 切片 mapValue, &mapValue, // 映射 chanValue, &chanValue, // 通道 structValue, &structValue, // 結構體 func1Value, &func1Value, // 定參函數 func2Value, &func2Value, // 動參函數 structValue.Method1, structValue.Method2, // 方法 unsafePointer, &unsafePointer, // 指針 reflectType, &reflectType, // 反射類型 reflectValue, &reflectValue, // 反射值 interfaceType, &interfaceType, // 接口反射類型 } // 空值 var unsafeP unsafe.Pointer // 空接口 var nilInterfece interface{} func main() { // 測試簡單類型 for i := 0; i < len(simpleTypes); i++ { PrintInfo(simpleTypes[i]) } // 測試複雜類型 for i := 0; i < len(complexTypes); i++ { PrintInfo(complexTypes[i]) } // 測試單個對象 PrintInfo(unsafeP) PrintInfo(&unsafeP) PrintInfo(nilInterfece) PrintInfo(&nilInterfece) } func PrintInfo(i interface{}) { if i == nil { fmt.Println("--------------------") fmt.Printf("無效接口值:%v\n", i) return } t := reflect.TypeOf(i) PrintType(t) } func PrintType(t reflect.Type) { fmt.Println("--------------------") // ----- 通用方法 ----- fmt.Println("String :", t.String()) // 類型字符串 fmt.Println("Name :", t.Name()) // 類型名稱 fmt.Println("PkgPath :", t.PkgPath()) // 所在包名稱 fmt.Println("Kind :", t.Kind()) // 所屬分類 fmt.Println("Size :", t.Size()) // 內存大小 fmt.Println("Align :", t.Align()) // 字節對齊 fmt.Println("FieldAlign :", t.FieldAlign()) // 字段對齊 fmt.Println("NumMethod :", t.NumMethod()) // 方法數量 if t.NumMethod() > 0 { i := 0 for ; i < t.NumMethod()-1; i++ { fmt.Println(" ┣", t.Method(i).Name) // 經過索引定位方法 } fmt.Println(" ┗", t.Method(i).Name) // 經過索引定位方法 } if sm, ok := t.MethodByName("String"); ok { // 經過名稱定位方法 fmt.Println("MethodByName :", sm.Index, sm.Name) } fmt.Println("Implements(i{}) :", t.Implements(interfaceType)) // 是否實現了指定接口 fmt.Println("ConvertibleTo(int) :", t.ConvertibleTo(reflectType)) // 是否可轉換爲指定類型 fmt.Println("AssignableTo(int) :", t.AssignableTo(reflectType)) // 是否可賦值給指定類型的變量 fmt.Println("Comparable :", t.Comparable()) // 是否可進行比較操做 // ----- 特殊類型 ----- switch t.Kind() { // 指針型: case reflect.Ptr: fmt.Println("=== 指針型 ===") // 獲取指針所指對象 t = t.Elem() fmt.Printf("轉換到指針所指對象 : %v\n", t.String()) // 遞歸處理指針所指對象 PrintType(t) return // 自由指針型: case reflect.UnsafePointer: fmt.Println("=== 自由指針 ===") // ... // 接口型: case reflect.Interface: fmt.Println("=== 接口型 ===") // ... } // ----- 簡單類型 ----- // 數值型: if reflect.Int <= t.Kind() && t.Kind() <= reflect.Complex128 { fmt.Println("=== 數值型 ===") fmt.Println("Bits :", t.Bits()) // 位寬 } // ----- 複雜類型 ----- switch t.Kind() { // 數組型: case reflect.Array: fmt.Println("=== 數組型 ===") fmt.Println("Len :", t.Len()) // 數組長度 fmt.Println("Elem :", t.Elem()) // 數組元素類型 // 切片型: case reflect.Slice: fmt.Println("=== 切片型 ===") fmt.Println("Elem :", t.Elem()) // 切片元素類型 // 映射型: case reflect.Map: fmt.Println("=== 映射型 ===") fmt.Println("Key :", t.Key()) // 映射鍵 fmt.Println("Elem :", t.Elem()) // 映射值類型 // 通道型: case reflect.Chan: fmt.Println("=== 通道型 ===") fmt.Println("ChanDir :", t.ChanDir()) // 通道方向 fmt.Println("Elem :", t.Elem()) // 通道元素類型 // 結構體: case reflect.Struct: fmt.Println("=== 結構體 ===") fmt.Println("NumField :", t.NumField()) // 字段數量 if t.NumField() > 0 { var i, j int // 遍歷結構體字段 for i = 0; i < t.NumField()-1; i++ { field := t.Field(i) // 獲取結構體字段 fmt.Printf(" ├ %v\n", field.Name) // 遍歷嵌套結構體字段 if field.Type.Kind() == reflect.Struct && field.Type.NumField() > 0 { for j = 0; j < field.Type.NumField()-1; j++ { subfield := t.FieldByIndex([]int{i, j}) // 獲取嵌套結構體字段 fmt.Printf(" │ ├ %v\n", subfield.Name) } subfield := t.FieldByIndex([]int{i, j}) // 獲取嵌套結構體字段 fmt.Printf(" │ └ %%v\n", subfield.Name) } } field := t.Field(i) // 獲取結構體字段 fmt.Printf(" └ %v\n", field.Name) // 經過名稱查找字段 if field, ok := t.FieldByName("ptr"); ok { fmt.Println("FieldByName(ptr) :", field.Name) } // 經過函數查找字段 if field, ok := t.FieldByNameFunc(func(s string) bool { return len(s) > 3 }); ok { fmt.Println("FieldByNameFunc :", field.Name) } } // 函數型: case reflect.Func: fmt.Println("=== 函數型 ===") fmt.Println("IsVariadic :", t.IsVariadic()) // 是否具備變長參數 fmt.Println("NumIn :", t.NumIn()) // 參數數量 if t.NumIn() > 0 { i := 0 for ; i < t.NumIn()-1; i++ { fmt.Println(" ┣", t.In(i)) // 獲取參數類型 } fmt.Println(" ┗", t.In(i)) // 獲取參數類型 } fmt.Println("NumOut :", t.NumOut()) // 返回值數量 if t.NumOut() > 0 { i := 0 for ; i < t.NumOut()-1; i++ { fmt.Println(" ┣", t.Out(i)) // 獲取返回值類型 } fmt.Println(" ┗", t.Out(i)) // 獲取返回值類型 } } } ------------------------------------------------------------ 接下來學習 reflect.Value 的全部方法,仍是進行分類學習,這裏的不少操做(好比取地址、取切片、修改映射、通道進出、取值、賦值、函數調用等)和平時的操做都同樣,只不過在這裏須要用各類方法來操做,而平時只須要用一些符號來操做。 注意:下面描述的 v 值是指 reflect.Value 所表明的實際值,而不是 reflect.Value 自己。 ------------------------------ // 特殊 // 判斷 v 值是否可尋址 // 一、指針的 Elem() 可尋址 // 二、切片的元素可尋址 // 三、可尋址數組的元素可尋址 // 四、可尋址結構體的字段可尋址,方法不可尋址 // 也就是說,若是 v 值是指向數組的指針「&數組」,經過 v.Elem() 獲取該指針指向的數組,那麼 // 該數組就是可尋址的,同時該數組的元素也是可尋址的,若是 v 就是一個普通數組,不是經過解引 // 用獲得的數組,那麼該數組就不可尋址,其元素也不可尋址。結構體亦然。 func (v Value) CanAddr() bool // 獲取 v 值的地址,至關於 & 取地址操做。v 值必須可尋址。 func (v Value) Addr() reflect.Value // 判斷 v 值是否能夠被修改。只有可尋址的 v 值可被修改。 // 結構體中的非導出字段(經過 Field() 等方法獲取的)不能修改,全部方法不能修改。 func (v Value) CanSet() bool // 判斷 v 值是否能夠轉換爲接口類型 // 結構體中的非導出字段(經過 Field() 等方法獲取的)不能轉換爲接口類型 func (v Value) CanInterface() bool // 將 v 值轉換爲空接口類型。v 值必須可轉換爲接口類型。 func (v Value) Interface() interface{} // 使用一對 uintptr 返回接口的數據 func (v Value) InterfaceData() [2]uintptr ------------------------------ // 示例: type ss struct { A int a int } func (s ss) Method1(i int) string { return "結構體方法1" } func (s *ss) Method2(i int) string { return "結構體方法2" } func main() { v1 := reflect.ValueOf(ss{}) // 結構體 v2 := reflect.ValueOf(&ss{}) // 結構體指針 v3 := reflect.ValueOf(&ss{}).Elem() // 可尋址結構體 v4 := reflect.ValueOf(&ss{}).Elem().Field(0) // 可尋址結構體的共有字段 v5 := reflect.ValueOf(&ss{}).Elem().Field(1) // 可尋址結構體的私有字段 v6 := reflect.ValueOf(&ss{}).Method(0) // 結構體指針的方法 v7 := reflect.ValueOf(&ss{}).Elem().Method(0) // 結構體的方法 fmt.Println(v1.CanAddr()) // false fmt.Println(v2.CanAddr()) // false fmt.Println(v3.CanAddr()) // true fmt.Println(v4.CanAddr()) // true fmt.Println(v5.CanAddr()) // true fmt.Println(v6.CanAddr()) // false fmt.Println(v7.CanAddr()) // false fmt.Println("----------") fmt.Println(v1.CanSet()) // false fmt.Println(v2.CanSet()) // false fmt.Println(v3.CanSet()) // true fmt.Println(v4.CanSet()) // true fmt.Println(v5.CanSet()) // false fmt.Println(v6.CanSet()) // false fmt.Println(v6.CanSet()) // false fmt.Println("----------") fmt.Println(v1.CanInterface()) // true fmt.Println(v2.CanInterface()) // true fmt.Println(v3.CanInterface()) // true fmt.Println(v4.CanInterface()) // true fmt.Println(v5.CanInterface()) // false fmt.Println(v6.CanInterface()) // true fmt.Println(v7.CanInterface()) // true } ------------------------------ // 指針 // 將 v 值轉換爲 uintptr 類型,v 值必須是切片、映射、通道、函數、指針、自由指針。 func (v Value) Pointer() uintptr // 獲取 v 值的地址。v 值必須是可尋址類型(CanAddr)。 func (v Value) UnsafeAddr() uintptr // 將 UnsafePointer 類別的 v 值修改成 x,v 值必須是 UnsafePointer 類別,必須可修改。 func (v Value) SetPointer(x unsafe.Pointer) // 判斷 v 值是否爲 nil,v 值必須是切片、映射、通道、函數、接口、指針。 // IsNil 並不總等價於 Go 的潛在比較規則,好比對於 var i interface{},i == nil 將返回 // true,可是 reflect.ValueOf(i).IsNil() 將 panic。 func (v Value) IsNil() bool // 獲取「指針所指的對象」或「接口所包含的對象」 func (v Value) Elem() reflect.Value ------------------------------ // 接口 // 獲取「指針所指的對象」或「接口所包含的對象」 func (v Value) Elem() reflect.Value ------------------------------ // 通用 // 獲取 v 值的字符串描述 func (v Value) String() string // 獲取 v 值的類型 func (v Value) Type() reflect.Type // 返回 v 值的類別,若是 v 是空值,則返回 reflect.Invalid。 func (v Value) Kind() reflect.Kind // 獲取 v 的方法數量 func (v Value) NumMethod() int // 根據索引獲取 v 值的方法,方法必須存在,不然 panic // 使用 Call 調用方法的時候不用傳入接收者,Go 會自動把 v 做爲接收者傳入。 func (v Value) Method(int) reflect.Value // 根據名稱獲取 v 值的方法,若是該方法不存在,則返回空值(reflect.Invalid)。 func (v Value) MethodByName(string) reflect.Value // 判斷 v 自己(不是 v 值)是否爲零值。 // 若是 v 自己是零值,則除了 String 以外的其它全部方法都會 panic。 func (v Value) IsValid() bool // 將 v 值轉換爲 t 類型,v 值必須可轉換爲 t 類型,不然 panic。 func (v Value) Convert(t Type) reflect.Value ------------------------------ // 示例 func main() { var v reflect.Value // 未包含任何數據 fmt.Println(v.IsValid()) // false var i *int v = reflect.ValueOf(i) // 包含一個指針 fmt.Println(v.IsValid()) // true v = reflect.ValueOf(nil) // 包含一個 nil 指針 fmt.Println(v.IsValid()) // false v = reflect.ValueOf(0) // 包含一個 int 數據 fmt.Println(v.IsValid()) // true } ------------------------------ // 獲取 // 獲取 v 值的內容,若是 v 值不是有符號整型,則 panic。 func (v Value) Int() int64 // 獲取 v 值的內容,若是 v 值不是無符號整型(包括 uintptr),則 panic。 func (v Value) Uint() uint64 // 獲取 v 值的內容,若是 v 值不是浮點型,則 panic。 func (v Value) Float() float64 // 獲取 v 值的內容,若是 v 值不是複數型,則 panic。 func (v Value) Complex() complex128 // 獲取 v 值的內容,若是 v 值不是布爾型,則 panic。 func (v Value) Bool() bool // 獲取 v 值的長度,v 值必須是字符串、數組、切片、映射、通道。 func (v Value) Len() int // 獲取 v 值的容量,v 值必須是數值、切片、通道。 func (v Value) Cap() int // 獲取 v 值的第 i 個元素,v 值必須是字符串、數組、切片,i 不能超出範圍。 func (v Value) Index(i int) reflect.Value // 獲取 v 值的內容,若是 v 值不是字節切片,則 panic。 func (v Value) Bytes() []byte // 獲取 v 值的切片,切片長度 = j - i,切片容量 = v.Cap() - i。 // v 必須是字符串、數值、切片,若是是數組則必須可尋址。i 不能超出範圍。 func (v Value) Slice(i, j int) reflect.Value // 獲取 v 值的切片,切片長度 = j - i,切片容量 = k - i。 // i、j、k 不能超出 v 的容量。i <= j <= k。 // v 必須是字符串、數值、切片,若是是數組則必須可尋址。i 不能超出範圍。 func (v Value) Slice3(i, j, k int) reflect.Value // 根據 key 鍵獲取 v 值的內容,v 值必須是映射。 // 若是指定的元素不存在,或 v 值是未初始化的映射,則返回零值(reflect.ValueOf(nil)) func (v Value) MapIndex(key Value) reflect.Value // 獲取 v 值的全部鍵的無序列表,v 值必須是映射。 // 若是 v 值是未初始化的映射,則返回空列表。 func (v Value) MapKeys() []reflect.Value // 判斷 x 是否超出 v 值的取值範圍,v 值必須是有符號整型。 func (v Value) OverflowInt(x int64) bool // 判斷 x 是否超出 v 值的取值範圍,v 值必須是無符號整型。 func (v Value) OverflowUint(x uint64) bool // 判斷 x 是否超出 v 值的取值範圍,v 值必須是浮點型。 func (v Value) OverflowFloat(x float64) bool // 判斷 x 是否超出 v 值的取值範圍,v 值必須是複數型。 func (v Value) OverflowComplex(x complex128) bool ------------------------------ // 設置(這些方法要求 v 值必須可修改) // 設置 v 值的內容,v 值必須是有符號整型。 func (v Value) SetInt(x int64) // 設置 v 值的內容,v 值必須是無符號整型。 func (v Value) SetUint(x uint64) // 設置 v 值的內容,v 值必須是浮點型。 func (v Value) SetFloat(x float64) // 設置 v 值的內容,v 值必須是複數型。 func (v Value) SetComplex(x complex128) // 設置 v 值的內容,v 值必須是布爾型。 func (v Value) SetBool(x bool) // 設置 v 值的內容,v 值必須是字符串。 func (v Value) SetString(x string) // 設置 v 值的長度,v 值必須是切片,n 不能超出範圍,不能爲負數。 func (v Value) SetLen(n int) // 設置 v 值的內容,v 值必須是切片,n 不能超出範圍,不能小於 Len。 func (v Value) SetCap(n int) // 設置 v 值的內容,v 值必須是字節切片。x 能夠超出 v 值容量。 func (v Value) SetBytes(x []byte) // 設置 v 值的鍵和值,若是鍵存在,則修改其值,若是鍵不存在,則添加鍵和值。 // 若是將 val 設置爲零值(reflect.ValueOf(nil)),則刪除該鍵。 // 若是 v 值是一個未初始化的 map,則 panic。 func (v Value) SetMapIndex(key, val reflect.Value) // 設置 v 值的內容,v 值必須可修改,x 必須能夠賦值給 v 值。 func (v Value) Set(x reflect.Value) ------------------------------ // 結構體 // 獲取 v 值的字段數量,v 值必須是結構體。 func (v Value) NumField() int // 根據索引獲取 v 值的字段,v 值必須是結構體。若是字段不存在則 panic。 func (v Value) Field(i int) reflect.Value // 根據索引鏈獲取 v 值的嵌套字段,v 值必須是結構體。 func (v Value) FieldByIndex(index []int) reflect.Value // 根據名稱獲取 v 值的字段,v 值必須是結構體。 // 若是指定的字段不存在,則返回零值(reflect.ValueOf(nil)) func (v Value) FieldByName(string) reflect.Value // 根據匹配函數 match 獲取 v 值的字段,v 值必須是結構體。 // 若是沒有匹配的字段,則返回零值(reflect.ValueOf(nil)) func (v Value) FieldByNameFunc(match func(string) bool) Value ------------------------------ // 示例 type ss struct { s struct { B int b int } A int a int } func main() { var v = reflect.ValueOf(ss{}) for i := 0; i < v.NumField(); i++ { field := v.Field(i) fmt.Println("字段:", field.Type().String()) if field.Type().Kind() == reflect.Struct { for j := 0; j < field.NumField(); j++ { subfield := field.Field(j) fmt.Println(" 嵌套字段:", subfield.Type().String()) } } } } // 輸出結果: // 字段: struct { B int; b int } // 嵌套字段: int // 嵌套字段: int // 字段: int // 字段: int ------------------------------ // 通道 // 發送數據(會阻塞),v 值必須是可寫通道。 func (v Value) Send(x reflect.Value) // 接收數據(會阻塞),v 值必須是可讀通道。 func (v Value) Recv() (x reflect.Value, ok bool) // 嘗試發送數據(不會阻塞),v 值必須是可寫通道。 func (v Value) TrySend(x reflect.Value) bool // 嘗試接收數據(不會阻塞),v 值必須是可讀通道。 func (v Value) TryRecv() (x reflect.Value, ok bool) // 關閉通道,v 值必須是通道。 func (v Value) Close() ------------------------------ // 示例 func main() { ch := make(chan int, 2) v := reflect.ValueOf(ch) a := reflect.ValueOf(1) b := reflect.ValueOf(2) v.Send(a) if ok := v.TrySend(b); ok { fmt.Println("嘗試發送成功!") // 嘗試發送成功! } if i, ok := v.Recv(); ok { fmt.Println("接收成功:", i) // 接收成功: 1 } if i, ok := v.TryRecv(); ok { fmt.Println("嘗試接收成功:", i) // 嘗試接收成功: 2 } } ------------------------------ // 函數 // 經過參數列表 in 調用 v 值所表明的函數(或方法)。函數的返回值存入 r 中返回。 // 要傳入多少參數就在 in 中存入多少元素。 // Call 便可以調用定參函數(參數數量固定),也能夠調用變參函數(參數數量可變)。 func (v Value) Call(in []Value) (r []Value) // 經過參數列表 in 調用 v 值所表明的函數(或方法)。函數的返回值存入 r 中返回。 // 函數指定了多少參數就在 in 中存入多少元素,變參做爲一個單獨的參數提供。 // CallSlice 只能調用變參函數。 func (v Value) CallSlice(in []Value) []Value ------------------------------ // 示例 var f1 = func(a int, b []int) { fmt.Println(a, b) } var f2 = func(a int, b ...int) { fmt.Println(a, b) } func main() { v1 := reflect.ValueOf(f1) v2 := reflect.ValueOf(f2) a := reflect.ValueOf(1) b := reflect.ValueOf([]int{1, 2, 3}) v1.Call([]reflect.Value{a, b}) v2.Call([]reflect.Value{a, a, a, a, a, a}) //v1.CallSlice([]reflect.Value{a, b}) // 非變參函數,不能用 CallSlice。 v2.CallSlice([]reflect.Value{a, b}) } ------------------------------ 下面的代碼用到了全部這些方法: ------------------------------ // 獲取各類值的相關信息 package main import ( "fmt" "reflect" "unsafe" ) // 嵌套結構體 type ss struct { a struct { int string } int string bool float64 } func (s ss) Method1(i int) string { return "結構體方法1" } func (s *ss) Method2(i int) string { return "結構體方法2" } var ( intValue = int(0) int8Value = int8(8) int16Value = int16(16) int32Value = int32(32) int64Value = int64(64) uIntValue = uint(0) uInt8Value = uint8(8) uInt16Value = uint16(16) uInt32Value = uint32(32) uInt64Value = uint64(64) byteValue = byte(0) runeValue = rune(0) uintptrValue = uintptr(0) boolValue = false stringValue = "stringValue" float32Value = float32(32) float64Value = float64(64) complex64Value = complex64(64) complex128Value = complex128(128) arrayValue = [5]string{} // 數組 sliceValue = []byte{0, 0, 0, 0, 0} // 切片 mapValue = map[string]int{} // 映射 chanValue = make(chan int, 2) // 通道 structValue = ss{ // 結構體 struct { int string }{10, "子結構體"}, 20, "結構體", false, 64.0, } func1Value = func(i int) string { // 函數(固定參數) return fmt.Sprintf("固定參數:%v", i) } func2Value = func(i ...int) string { // 函數(動態參數) return fmt.Sprintf("動態參數:%v", i) } unsafePointer = unsafe.Pointer(&structValue) // 通用指針 reflectType = reflect.TypeOf(0) // 反射類型 reflectValue = reflect.ValueOf(0) // 反射值 reflectArrayValue = reflect.ValueOf([]int{1, 2, 3}) // 切片反射值 // 反射接口類型 interfaceType = reflect.TypeOf(new(interface{})).Elem() ) // 簡單類型 var simpleTypes = []interface{}{ intValue, &intValue, // int int8Value, &int8Value, // int8 int16Value, &int16Value, // int16 int32Value, &int32Value, // int32 int64Value, &int64Value, // int64 uIntValue, &uIntValue, // uint uInt8Value, &uInt8Value, // uint8 uInt16Value, &uInt16Value, // uint16 uInt32Value, &uInt32Value, // uint32 uInt64Value, &uInt64Value, // uint64 byteValue, &byteValue, // byte runeValue, &runeValue, // rune uintptrValue, &uintptrValue, // uintptr boolValue, &boolValue, // bool stringValue, &stringValue, // string float32Value, &float32Value, // float32 float64Value, &float64Value, // float64 complex64Value, &complex64Value, // complex64 complex128Value, &complex128Value, // complex128 } // 複雜類型 var complexTypes = []interface{}{ arrayValue, &arrayValue, // 數組 sliceValue, &sliceValue, // 切片 mapValue, &mapValue, // 映射 chanValue, &chanValue, // 通道 structValue, &structValue, // 結構體 func1Value, &func1Value, // 定參函數 func2Value, &func2Value, // 動參函數 structValue.Method1, structValue.Method2, // 方法 unsafePointer, &unsafePointer, // 指針 reflectType, &reflectType, // 反射類型 reflectValue, &reflectValue, // 反射值 interfaceType, &interfaceType, // 接口反射類型 } // 空值 var unsafeP unsafe.Pointer // 空接口 var nilInterfece interface{} func main() { // 測試簡單類型 for i := 0; i < len(simpleTypes); i++ { PrintInfo(simpleTypes[i]) } // 測試複雜類型 for i := 0; i < len(complexTypes); i++ { PrintInfo(complexTypes[i]) } // 測試單個對象 PrintInfo(&unsafeP) PrintInfo(nilInterfece) // PrintInfo(&nilInterfece) // 會引起 panic } func PrintInfo(i interface{}) { if i == nil { fmt.Println("--------------------") fmt.Printf("無效接口值:%v\n", i) fmt.Println("--------------------") return } v := reflect.ValueOf(i) PrintValue(v) } func PrintValue(v reflect.Value) { fmt.Println("--------------------") // ----- 通用方法 ----- fmt.Println("String :", v.String()) // 反射值的字符串形式 fmt.Println("Type :", v.Type()) // 反射值的類型 fmt.Println("Kind :", v.Kind()) // 反射值的類別 fmt.Println("CanAddr :", v.CanAddr()) // 是否能夠獲取地址 fmt.Println("CanSet :", v.CanSet()) // 是否能夠修改 if v.CanAddr() { fmt.Println("Addr :", v.Addr()) // 獲取地址 fmt.Println("UnsafeAddr :", v.UnsafeAddr()) // 獲取自由地址 } // 是否可轉換爲接口對象 fmt.Println("CanInterface :", v.CanInterface()) if v.CanInterface() { fmt.Println("Interface :", v.Interface()) // 轉換爲接口對象 } // 獲取方法數量 fmt.Println("NumMethod :", v.NumMethod()) if v.NumMethod() > 0 { // 遍歷方法 i := 0 for ; i < v.NumMethod()-1; i++ { fmt.Printf(" ┣ %v\n", v.Method(i).String()) // if i >= 4 { // 只列舉 5 個 // fmt.Println(" ┗ ...") // break // } } fmt.Printf(" ┗ %v\n", v.Method(i).String()) // 經過名稱獲取方法 fmt.Println("MethodByName :", v.MethodByName("String").String()) } // ----- 可獲取指針的類型 ----- switch v.Kind() { case reflect.Slice, reflect.Map, reflect.Chan, reflect.Func, reflect.Ptr, reflect.UnsafePointer: fmt.Println("Pointer :", v.Pointer()) } // ----- 特殊類型 ----- switch v.Kind() { // 指針: case reflect.Ptr: fmt.Println("=== 指針 ===") // 獲取指針地址 if !v.IsNil() { // 獲取指針所指對象 v = v.Elem() // 只有指針和接口類型可使用 Elem() fmt.Printf("轉換到指針所指對象 : %v\n", v.Type()) // 遞歸處理指針所指對象 PrintValue(v) return } // 自由指針: case reflect.UnsafePointer: fmt.Println("=== 自由指針 ===") if v.Pointer() == 0 { v.SetPointer(unsafePointer) fmt.Println("從新指向新對象 :", v.Pointer()) } // 將自由指針轉換爲 *ss 指針(由於定義 unsafePointer 時已經肯定了類型) s := (*ss)(v.Interface().(unsafe.Pointer)) // 獲取反射值 v = reflect.ValueOf(s) if !v.IsNil() { // 獲取指針所指對象 v = v.Elem() // 只有指針和接口類型可使用 Elem() fmt.Printf("轉換到指針所指對象 : %v\n", v.Type()) // 遞歸處理指針所指對象 PrintValue(v) return } // 接口: case reflect.Interface: fmt.Println("=== 接口 ===") // 獲取接口數據 fmt.Println("InterfaceData :", v.InterfaceData()) // 獲取接口所包含的對象 v = v.Elem() // 只有指針和接口類型可使用 Elem() fmt.Printf("轉換到接口所含對象 : %v\n", v.Type()) // 遞歸處理接口的動態對象 PrintValue(v) return } // ----- 簡單類型 ----- // 有符號整型: if reflect.Int <= v.Kind() && v.Kind() <= reflect.Int64 { fmt.Println("=== 有符號整型 ===") fmt.Println("Int :", v.Int()) // 獲取值 if v.CanSet() { v.SetInt(10) // 設置值 fmt.Println("Int :", v.Int()) // 獲取值 v.Set(reflect.ValueOf(20).Convert(v.Type())) // 設置值 } fmt.Println("Int :", v.Int()) // 獲取值 fmt.Println("OverflowInt :", v.OverflowInt(10)) // 是否溢出 } // 無符號整型: if reflect.Uint <= v.Kind() && v.Kind() <= reflect.Uint64 { fmt.Println("=== 無符號整型 ===") fmt.Println("Uint :", v.Uint()) // 獲取值 if v.CanSet() { v.SetUint(10) // 設置值 fmt.Println("Uint :", v.Uint()) // 獲取值 v.Set(reflect.ValueOf(20).Convert(v.Type())) // 設置值 } fmt.Println("Uint :", v.Uint()) // 獲取值 fmt.Println("OverflowUint :", v.OverflowUint(10)) // 是否溢出 } switch v.Kind() { // 浮點數: case reflect.Float32, reflect.Float64: fmt.Println("=== 浮點數 ===") fmt.Println("Float :", v.Float()) // 獲取值 if v.CanSet() { v.SetFloat(10) // 設置值 fmt.Println("Float :", v.Float()) // 獲取值 v.Set(reflect.ValueOf(20).Convert(v.Type())) // 設置值 } fmt.Println("Float :", v.Float()) // 獲取值 fmt.Println("OverflowFloat :", v.OverflowFloat(10)) // 是否溢出 // 複數: case reflect.Complex64, reflect.Complex128: fmt.Println("=== 複數 ===") fmt.Println("Complex :", v.Complex()) // 獲取值 if v.CanSet() { v.SetComplex(10) // 設置值 fmt.Println("Complex :", v.Complex()) // 獲取值 v.Set(reflect.ValueOf(20 + 20i).Convert(v.Type())) // 設置值 } fmt.Println("Complex :", v.Complex()) // 獲取值 fmt.Println("OverflowComplex :", v.OverflowComplex(10)) // 是否溢出 // 布爾型: case reflect.Bool: fmt.Println("=== 布爾型 ===") fmt.Println("Bool :", v.Bool()) // 獲取值 if v.CanSet() { v.SetBool(true) // 設置值 fmt.Println("Bool :", v.Bool()) // 獲取值 v.Set(reflect.ValueOf(false)) // 設置值 } fmt.Println("Bool :", v.Bool()) // 獲取值 // 字符串: case reflect.String: fmt.Println("=== 字符串 ===") fmt.Println("String :", v.String()) // 獲取值 if v.CanSet() { v.SetString("abc") // 設置值 fmt.Println("String :", v.String()) // 獲取值 v.Set(reflect.ValueOf("def")) // 設置值 } fmt.Println("String :", v.String()) // 獲取值 // ----- 複雜類型 ----- // 切片型: case reflect.Slice: fmt.Println("=== 切片型 ===") fmt.Println("Len :", v.Len()) // 獲取長度 fmt.Println("Cap :", v.Cap()) // 獲取容量 if v.CanSet() { v.SetLen(4) // 不能大於 cap v.SetCap(4) // 不能小於 len,只能縮,不能擴 fmt.Println("SetLen, SetCap :", v.Len(), v.Cap()) // 從新指定字節內容 if v.Type().Elem().Kind() == reflect.Uint8 { v.SetBytes([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}) } fmt.Println("SetByte :", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}) } // 獲取字節內容 if v.Type().Elem().Kind() == reflect.Uint8 { fmt.Println("Bytes :", v.Bytes()) } // 根據索引獲取元素 if v.Len() > 0 { for i := 0; i < v.Len(); i++ { fmt.Println("Index :", v.Index(i)) } } // 獲取一個指定範圍的切片 // 參數:起始下標,結束下標 // 長度 = 結束下標 - 起始下標 s1 := v.Slice(1, 2) fmt.Println("Slice :", s1) fmt.Println("Len :", s1.Len()) // 獲取長度 fmt.Println("Cap :", s1.Cap()) // 獲取容量 // 獲取一個指定範圍和容量的切片 // 參數:起始下標,結束下標,容量下標 // 長度 = 結束下標 - 起始下標 // 容量 = 容量下標 - 起始下標 s2 := v.Slice3(1, 2, 4) fmt.Println("Slice :", s2) fmt.Println("Len :", s2.Len()) // 獲取長度 fmt.Println("Cap :", s2.Cap()) // 獲取容量 // 映射型: case reflect.Map: fmt.Println("=== 映射型 ===") // 設置鍵值,不須要檢測 CanSet v.SetMapIndex(reflect.ValueOf("a"), reflect.ValueOf(1)) v.SetMapIndex(reflect.ValueOf("b"), reflect.ValueOf(2)) v.SetMapIndex(reflect.ValueOf("c"), reflect.ValueOf(3)) // 獲取鍵列表 fmt.Println("MapKeys :", v.MapKeys()) for _, idx := range v.MapKeys() { // 根據鍵獲取值 fmt.Println("MapIndex :", v.MapIndex(idx)) } // 結構體: case reflect.Struct: fmt.Println("=== 結構體 ===") // 獲取字段個數 fmt.Println("NumField :", v.NumField()) if v.NumField() > 0 { var i, j int // 遍歷結構體字段 for i = 0; i < v.NumField()-1; i++ { field := v.Field(i) // 獲取結構體字段 fmt.Printf(" ├ %-8v %v\n", field.Type(), field.String()) // 遍歷嵌套結構體字段 if field.Kind() == reflect.Struct && field.NumField() > 0 { for j = 0; j < field.NumField()-1; j++ { subfield := v.FieldByIndex([]int{i, j}) // 獲取嵌套結構體字段 fmt.Printf(" │ ├ %-8v %v\n", subfield.Type(), subfield.String()) // if i >= 4 { // 只列舉 5 個 // fmt.Println(" ┗ ...") // break // } } subfield := v.FieldByIndex([]int{i, j}) // 獲取嵌套結構體字段 fmt.Printf(" │ └ %-8v %v\n", subfield.Type(), subfield.String()) } // if i >= 4 { // 只列舉 5 個 // fmt.Println(" ┗ ...") // break // } } field := v.Field(i) // 獲取結構體字段 fmt.Printf(" └ %-8v %v\n", field.Type(), field.String()) // 經過名稱查找字段 if v := v.FieldByName("ptr"); v.IsValid() { fmt.Println("FieldByName(ptr) :", v.Type().Name()) } // 經過函數查找字段 v := v.FieldByNameFunc(func(s string) bool { return len(s) > 3 }) if v.IsValid() { fmt.Println("FieldByNameFunc :", v.Type().Name()) } } // 通道型: case reflect.Chan: fmt.Println("=== 通道型 ===") // 發送數據(會阻塞) v.Send(reflectValue) // 嘗試發送數據(不會阻塞) fmt.Println("TrySend :", v.TrySend(reflectValue)) // 接收數據(會阻塞) if x, ok := v.Recv(); ok { fmt.Println("Recv :", x) // } // 嘗試接收數據(不會阻塞) if x, ok := v.TryRecv(); ok { fmt.Println("TryRecv :", x) // } // 由於要執行兩次,通道和通道指針各執行一次,關閉後第二次就沒法執行了。 // v.Close() // 函數型: case reflect.Func: fmt.Println("=== 函數型 ===") // 判斷函數是否具備變長參數 if v.Type().IsVariadic() { // 與可變參數對應的實參必須是切片類型的反射值(reflectArrayValue)。 fmt.Println("CallSlice :", v.CallSlice([]reflect.Value{reflectArrayValue})) // // 也能夠用 v.Call 調用變長參數的函數,只需傳入 reflectValue 便可。 } else { // 根據函數定義的參數數量,傳入相應數量的反射值(reflectValue)。 fmt.Println("Call :", v.Call([]reflect.Value{reflectValue})) // } } } ------------------------------------------------------------