項目中有多處用到反射,本文簡單列舉go中提供反射的常用case。
go reflect反射包,通過 Type和Value 分別表示反射獲取的類型和值。通過函數,reflect.TypeOf 和 reflect.ValueOf,返回被檢查對象的類型和值。例如,x 被定義爲:var x float64 = 3.4,那麼 reflect.TypeOf(x) 返回 float64,reflect.ValueOf(x) 返回 3.4
通過反射獲取變量信息
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
v := reflect.ValueOf(x)
fmt.Println("value:", v)
fmt.Println("type:", v.Type())
fmt.Println("kind:", v.Kind())
fmt.Println("value:", v.Float())
fmt.Println(v.Interface())
fmt.Printf("value is %5.2e\n", v.Interface())
y := v.Interface().(float64)
fmt.Println(y)
}
輸出:
type: float64
value: 3.4
type: float64
kind: float64
value: 3.4
3.4
value is 3.40e+00
3.4
注:x 是一個 float64 類型的值,reflect.ValueOf(x).Float()
返回這個 float64 類型的實際值;同樣的適用於 Int(), Bool(), Complex(), String()
通過反射修改值
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
v := reflect.ValueOf(x)
// setting a value:
// v.SetFloat(3.1415) // Error: will panic: reflect.Value.SetFloat using unaddressable value 原因是 v 不是可設置的
fmt.Println("settability of v:", v.CanSet()) //可以使用 CanSet() 方法測試是否可設置
v = reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println("type of v:", v.Type())
fmt.Println("settability of v:", v.CanSet())
//要想讓其可設置我們需要使用 Elem() 函數,這間接的使用指針:v = v.Elem()
v = v.Elem()
fmt.Println("The Elem of v is: ", v)
fmt.Println("settability of v:", v.CanSet())
v.SetFloat(3.1415) // this works!
fmt.Println(v.Interface())
fmt.Println(v)
}
輸出:
settability of v: false
type of v: *float64
settability of v: false
The Elem of v is: <float64 Value>
settability of v: true
3.1415
<float64 Value>
反射中有些內容是需要用地址去改變它的狀態值等信息。
反射結構體
package main
import (
"fmt"
"reflect"
)
type NotknownType struct {
s1, s2, s3 string
}
func (n NotknownType) String() string {
return n.s1 + " - " + n.s2 + " - " + n.s3
}
// variable to investigate:
var secret interface{} = NotknownType{"Ada", "Go", "Oberon"}
func main() {
value := reflect.ValueOf(secret) // <main.NotknownType Value>
typ := reflect.TypeOf(secret) // main.NotknownType
//typ := value.Type() // main.NotknownType
fmt.Println(typ)
knd := value.Kind() // struct
fmt.Println(knd)
// iterate through the fields of the struct: value.NumField()反射遍歷結構體屬性
for i := 0; i < value.NumField(); i++ {
//value.Field獲取值
fmt.Printf("Field %d: %v\n", i, value.Field(i))
// error: panic: reflect.Value.SetString using value obtained using unexported field
//結構中只有被導出字段(首字母大寫)纔是可設置的
//value.Field(i).SetString("C#")
}
// call the first method, which is String():
results := value.Method(0).Call(nil)
fmt.Println(results) // [Ada - Go - Oberon]
}
輸出:
main.NotknownType
struct
Field 0: Ada
Field 1: Go
Field 2: Oberon
[Ada - Go - Oberon]