反射的知識點比較晦澀,後期會對此知識點展開深入的分析及範例程式碼展示
反射可達大提高程式的靈活性,使得inferface{}有更大的發揮餘地
反射使用TypeOf和ValueOf函數從介面中擷取目標對象資訊:欄位屬性,方法資訊
package mainimport ( "fmt" "reflect")type User struct { //定義一個結構類型 Id int Name string Age int}func (u User) Hello() { //定義一個結構方法 fmt.Println("Hello world")}func Info(o interface{}) { //定義一個方法,參數為空白介面 t := reflect.TypeOf(o) //擷取接收到的介面類型 fmt.Println("Type:", t.Name()) //擷取名稱 v := reflect.ValueOf(o) //擷取介面的欄位 fmt.Println("Fields:") //擷取結構欄位 for i := 0; i < t.NumField(); i++ { //for迴圈,取出所擁有的欄位 f := t.Field(i) //擷取值欄位 val := v.Field(i).Interface() //擷取欄位的值 fmt.Printf("%6s:%v=%v\n", f.Name, f.Type, val) } //通過介面擷取結構的方法 for i := 0; i < t.NumMethod(); i++ { m := t.Method(i) fmt.Printf("%6s:%v\n", m.Name, m.Type) }}func main() { u := User{1, "OK", 12} //執行個體化一個結構 Info(u) //調用Info函數}/*輸出 Type: User Fields: Id:int=1 Name:string=OK Age:int=12 Hello:func(main.User)*/
反射會將匿名欄位作為獨立欄位(匿名欄位本質)
package mainimport ( "fmt" "reflect")type User struct { //定義一個結構類型 Id int Name string Age int}type Manager struct { User //嵌入User結構,User就是Manager結構的匿名欄位 title string}func main() { m := Manager{User: User{1, "mm", 27}, title: "name"} //注意初始化方式 t := reflect.TypeOf(m) //傳遞結構 fmt.Printf("%#v\n", t.Field(0)) //擷取索引為0的欄位資訊,即User欄位資訊 fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 0})) //根據索引取出ID的欄位資訊()} //{0,0}--User在Manager索引為0,ID在User索引為0/*output reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x4ac220), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}"Anonymous:true" 其中包含Anonymous(匿名)欄位*/
想要利用反射修改對象狀態,前提是interface.data是settable,即pointer-interface(指標介面)
//這是一個簡單的修改對象狀態package mainimport ( "fmt" "reflect")func main() { x := 123 //底層類型是int類型 v := reflect.ValueOf(&x) //傳遞x的指標 v.Elem().SetInt(999) //通過方法修改x變數的值 fmt.Println(x)}/*輸出x---> 999*/
//通過反射修改結構欄位package mainimport ( "fmt" "reflect")type User struct { Name string ID int Age int}func main() { u := User{"MAOZI", 1, 22} Set(&u) fmt.Println(u)}func Set(o interface{}) { v := reflect.ValueOf(o) if v.Kind() != reflect.Ptr && !v.Elem().CanSet() { //判斷是否為反射typestring,且可以被修改 fmt.Println("fuck") return } else { //如果條件都滿足 v = v.Elem() } f := v.FieldByName("Name") //通過名欄位名找欄位 if !f.IsValid() { //IsValid方法判斷是否找了欄位 fmt.Println("invalid") return } if f.Kind() == reflect.String { f.SetString("momo") }}/*輸出{momo 1 22}*/
通過反射可以"動態"調用方法
//通過反射動態調用結構方法package mainimport ( "fmt" "reflect")type User struct { Name string ID int Age int}func (u User) Hello(name string) { fmt.Println("Hello", name, ",my name is", u.Name)}func main() { u := User{"Golang", 1, 22} v := reflect.ValueOf(u) mv := v.MethodByName("Hello") //反射:通過名字找結構欄位資訊 args := []reflect.Value{reflect.ValueOf("Python")} mv.Call(args)}/*輸出Hello Python ,my name is Golang*/