煩惱可以做網(wǎng)站嗎搜索熱度查詢
Golang 進(jìn)階5—— 反射
注意,該文檔只適合有編程基礎(chǔ)的同學(xué),這里的go教程只給出有區(qū)別的知識點(diǎn)
反射:
- 反射可以在運(yùn)行時(shí)動(dòng)態(tài)獲取變量的各種信息, 比如變量的類型、 類別等信息。
- 如果是結(jié)構(gòu)體變量,還可以獲取結(jié)構(gòu)體本身的信息(結(jié)構(gòu)體的字段、方法)。
- 通過反射, 可以修改變量的值,可以調(diào)用關(guān)聯(lián)的方法。
- 使用反射, 需要import(“reflect”)
1.1 main函數(shù)
package mainimport ("fmt""reflect"
)// 利用一個(gè)函數(shù), 函數(shù)的參數(shù)定義為空接口
// 空接口沒有任何方法,所以可以理解為所有類型都實(shí)現(xiàn)了空接口
// 也可以理解為我們可以把任何一種類型賦值給空接口
func testReflect (data interface{}) {// 1、 調(diào)用 TypeOf函數(shù), 返回reflect.Type 類型的數(shù)據(jù)fmt.Println("data type is ", reflect.TypeOf(data))// 2、 調(diào)用 ValueOf函數(shù), 返回reflect.Value 類型的數(shù)據(jù)reVal := reflect.ValueOf(data)fmt.Println("data value is ", reVal)// 3、 如果要獲取具體類型的值, 可以調(diào)用 Int 方法sum := 100 + reVal.Int()fmt.Println("sum is ", sum)// 4、 reVal 轉(zhuǎn)成空接口i2 := reVal.Interface()fmt.Println("i2 is ", i2)// 5、類型斷言n := i2.(int)n2 := n + 200fmt.Println("n2 is ", n2)fmt.Println("i2 type is ", reflect.TypeOf(i2))
}
1.2 輸出結(jié)果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
data type is int
data value is 10
sum is 110
i2 is 10
n2 is 210
i2 type is int
1.3 結(jié)構(gòu)體情況
import ("fmt""reflect"
)type Student struct {Name stringAge int
}// 利用一個(gè)函數(shù), 函數(shù)的參數(shù)定義為空接口
// 空接口沒有任何方法,所以可以理解為所有類型都實(shí)現(xiàn)了空接口
// 也可以理解為我們可以把任何一種類型賦值給空接口
func testReflect (data interface{}) {// 1、 調(diào)用 TypeOf函數(shù), 返回reflect.Type 類型的數(shù)據(jù)fmt.Println("data type is ", reflect.TypeOf(data))// 2、 調(diào)用 ValueOf函數(shù), 返回reflect.Value 類型的數(shù)據(jù)reVal := reflect.ValueOf(data)fmt.Println("data value is ", reVal)// 3、 reVal 轉(zhuǎn)成空接口i2 := reVal.Interface()fmt.Println("i2 is ", i2)if s, ok := i2.(Student); ok {fmt.Println("i2 is student:", s.Name)} else {fmt.Println("i2 is not a student")}
}func main () {stu1 := Student{"xiaoxiao", 18}testReflect(stu1)
}
1.4 輸出結(jié)果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
data type is main.Student
data value is {xiaoxiao 18}
i2 is {xiaoxiao 18}
i2 is student: xiaoxiao
1.5 獲取變量類別
import ("fmt""reflect"
)type Student struct {Name stringAge int
}// 利用一個(gè)函數(shù), 函數(shù)的參數(shù)定義為空接口
// 空接口沒有任何方法,所以可以理解為所有類型都實(shí)現(xiàn)了空接口
// 也可以理解為我們可以把任何一種類型賦值給空接口
func testReflect (data interface{}) {// 1、 調(diào)用 TypeOf函數(shù), 返回reflect.Type 類型的數(shù)據(jù)reType := reflect.TypeOf(data)fmt.Println("data type is ", reType)// 2、 調(diào)用 ValueOf函數(shù), 返回reflect.Value 類型的數(shù)據(jù)reVal := reflect.ValueOf(data)fmt.Println("data value is ", reVal)// 3、 獲取變量的類別(大范圍)k1 := reVal.Kind()fmt.Println("data kind is ", k1)k2 := reType.Kind()fmt.Println("data kind is ", k2)// 4、 獲取變量的類型 (小范圍)i2 := reVal.Interface()if n, ok := i2.(Student); ok {fmt.Println("n is ", n)} else {fmt.Println("n is not Student")}}func main () {stu1 := Student{"xiaoxiao", 18}testReflect(stu1)
}
1.6 輸出結(jié)果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
data type is main.Student
data value is {xiaoxiao 18}
data kind is struct
data kind is struct
n is {xiaoxiao 18}
1.7 對結(jié)構(gòu)體操作
// 1. 定義結(jié)構(gòu)體
type Student struct {Name stringAge int
}// 2. 給結(jié)構(gòu)體綁定方法
func (stu Student) Print() {fmt.Print("調(diào)用了Print方法")fmt.Println(stu)
}func (stu Student) GetSum(n1, n2 int) int {return n1 + n2
}func (stu Student) Set(name string, age int) {stu.Name = namestu.Age = age
}func testReflect(data interface{}) {reVal := reflect.ValueOf(data)// 檢查 data 是否是指針,并獲取指向的值if reVal.Kind() == reflect.Ptr {reVal = reVal.Elem()}fmt.Println(reVal)// 獲取結(jié)構(gòu)體中字段的數(shù)量n1 := reVal.NumField()fmt.Println("字段的數(shù)量:", n1)for i := 0; i < n1; i++ {// 輸出字段fmt.Printf("字段 %d 的名字是 %s, 對應(yīng)的值為 %v \n", i, reVal.Type().Field(i).Name, reVal.Field(i))}// 獲取結(jié)構(gòu)體的方法數(shù)量n2 := reVal.NumMethod()fmt.Println("方法的數(shù)量:", n2)// 輸出方法for i := 0; i < n2; i++ {// 輸出方法fmt.Printf("方法 %d 的名字是 %s \n", i, reVal.Type().Method(i).Name)}// 調(diào)用方法, 調(diào)用的方法首字母必須大寫reVal.MethodByName("Print").Call(nil)// 調(diào)用GetSum方法// 定義Value切片var params []reflect.Valueparams = append(params, reflect.ValueOf(10))params = append(params, reflect.ValueOf(20))sum := reVal.MethodByName("GetSum").Call(params)fmt.Println("sum = ", sum[0])
}func main() {stu := Student{Name: "Tom", Age: 18}testReflect(stu) // 傳入 stu 的指針
}
1.8 輸出結(jié)果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
{Tom 18}
字段的數(shù)量: 2
字段 0 的名字是 Name, 對應(yīng)的值為 Tom
字段 1 的名字是 Age, 對應(yīng)的值為 18
方法的數(shù)量: 3
方法 0 的名字是 GetSum
方法 1 的名字是 Print
方法 2 的名字是 Set
調(diào)用了Print方法{Tom 18}
sum = 30
1.9 改值
import ("fmt""reflect"
)// 1. 定義結(jié)構(gòu)體
type Student struct {Name stringAge int
}// 2. 給結(jié)構(gòu)體綁定方法
func (stu Student) Print() {fmt.Print("調(diào)用了Print方法")fmt.Println(stu)
}func (stu Student) GetSum(n1, n2 int) int {return n1 + n2
}func (stu Student) Set(name string, age int) {stu.Name = namestu.Age = age
}func testReflect(data interface{}) {reVal := reflect.ValueOf(data)// 通過setInt方法修改值n := reVal.Elem().NumField()fmt.Println("結(jié)構(gòu)體中字段個(gè)數(shù)為:", n)reVal.Elem().Field(0).SetString("Jack")reVal.Elem().Field(1).SetInt(30)
}func main() {stu := Student{Name: "Tom", Age: 18}testReflect(&stu) // 傳入 stu 的指針fmt.Println(stu)
}
1.10 輸出結(jié)果
(base) PS E:\Goproject\src\gocode\testproject03> go run .\main\main.go
結(jié)構(gòu)體中字段個(gè)數(shù)為: 2
{Jack 30}