Golang 反射 && 單元測(cè)試
一.反射
1 package reflecttest 2 3 import ( 4 "fmt" 5 "reflect" 6 ) 7 8 // 語(yǔ)法:const [name] [type] = [value] 9 // const 只能修飾int\float\string\bool作為常量 10 const ss string = "123" 11 const ( 12 a = iota // a是0,往后依次遞增1 13 b 14 c 15 d 16 ) 17 18 /* 19 反射: 20 1.反射可以在運(yùn)行時(shí)動(dòng)態(tài)獲取變量的各種信息,比如變量的類型(type),類別(kind) 21 2.如果是結(jié)構(gòu)體變量,還可以獲取到結(jié)構(gòu)體本身的信息(包括結(jié)構(gòu)體的字段、方法) 22 3.通過(guò)反射,可以修改變量的值,可以調(diào)用關(guān)聯(lián)的方法 23 4.使用反射,需要import("reflect") 24 5.變量、interface{}、reflect.Value時(shí)可以相互轉(zhuǎn)換的。 25 */ 26 27 func TestReflect(b interface{}) { 28 // 1.將interface{}專成reflect.Value 29 rVal := reflect.ValueOf(b) 30 31 // 2.將reflect.Value轉(zhuǎn)成interface{} 32 iVal := rVal.Interface() 33 34 // 3.獲取kind常量 35 fmt.Printf("kind=%v, type=%T\n", rVal.Kind(), rVal.Kind()) // reflect.Kind 36 37 // 4.將interface{}專程原來(lái)的變量類型 38 switch iVal.(type) { 39 case int: 40 fmt.Println("int") 41 // 4.轉(zhuǎn)reflect.Type 42 reflect.ValueOf(iVal.(int)) // 返回的就是:reflect.Type 43 rVal.Type() // 返回的就是:reflect.Type 44 fmt.Printf("kind=%v\n", rVal.Type().Kind()) 45 default: 46 fmt.Println("err type!") 47 } 48 49 } 50 51 func TestStructReflect() { 52 var ss string = "Tom" 53 TestElem := func(b interface{}) { 54 // 1.讀取reflectValue 55 rVal := reflect.ValueOf(b) 56 // 2.Kind 57 fmt.Println("Kind=", rVal.Kind()) 58 // 3.設(shè)置值. 59 // 通過(guò)反射來(lái)修改變量,注意當(dāng)使用SetXxx方法來(lái)設(shè)置時(shí),需要通過(guò)對(duì)應(yīng)的指針類型來(lái)完成,這樣才能改變傳入變量的值,同時(shí)需要使用到reflect.Value.Elem()方法 60 // 因?yàn)閞Val是指針,我們的目的是修改指針指向的內(nèi)容.這里rVal.Elem()的作用是,將rVal包裝成可修改指針指向內(nèi)容值的reflect.Value返回 61 rVal.Elem().SetString("123456789") 62 // rVal.SetInt(1) 63 } 64 fmt.Println(&ss) 65 TestElem(&ss) 66 fmt.Println(&ss) 67 fmt.Println(ss) 68 }
1 package reflecttest 2 3 import ( 4 "fmt" 5 "reflect" 6 ) 7 8 type Monster struct { 9 Name string `json:"name"` 10 Age int `json:"age"` 11 Score float32 `json:"score"` 12 Sex string 13 } 14 15 /* 顯示值 */ 16 func (self *Monster) Print() { 17 fmt.Println("-----start--------") 18 fmt.Println(*self) 19 fmt.Println("-----end--------") 20 } 21 22 /* 返回兩個(gè)數(shù)的和 */ 23 func (self *Monster) GetSum(a int, b int) int { 24 return a + b 25 } 26 27 /* 賦值 */ 28 func (self *Monster) SetValue(name string, age int, score float32, sex string) { 29 self.Name = name 30 self.Age = age 31 self.Score = score 32 self.Sex = sex 33 } 34 35 // 反射字段標(biāo)簽的用法 36 func TestStructFieldTag(b interface{}) { 37 // 獲取reflect.Type 38 typ := reflect.TypeOf(b) 39 typ1 := reflect.TypeOf(b) 40 // 獲取reflect.Value 41 val := reflect.ValueOf(b) 42 val1 := reflect.ValueOf(b) 43 // 獲取對(duì)應(yīng)的類型 44 kd := val.Kind() 45 if kd == reflect.Ptr { 46 val = val.Elem() 47 kd = val.Kind() 48 typ = val.Type() 49 } 50 // 如果不是結(jié)構(gòu)體就退出 51 if kd != reflect.Struct { 52 fmt.Println("傳入的值必須是struct類型.") 53 return 54 } 55 56 // 獲取該結(jié)構(gòu)體有幾個(gè)字段 57 num := val.NumField() 58 fmt.Printf("%v 結(jié)構(gòu)體有%v個(gè)字段.\n", typ, num) 59 // 獲取每個(gè)字段的值,以及字段設(shè)定的標(biāo)簽 60 for i := 0; i < num; i++ { 61 fmt.Printf("字段%v,值=%v\n", typ.Field(i).Name, val.Field(i)) 62 // 注意:獲取字段標(biāo)簽值,需要通過(guò)reflect.Type來(lái)獲取 63 tagVal := typ.Field(i).Tag.Get("json") 64 if tagVal != "" { 65 fmt.Printf("字段'%v',標(biāo)簽=%v\n", typ.Field(i).Name, tagVal) 66 } 67 if typ.Field(i).Name == "Name" { 68 // 修改字段值 69 val.Field(i).SetString("ReName") 70 } 71 } 72 73 // 獲取該結(jié)構(gòu)體有多少個(gè)方法 74 num = val.NumMethod() 75 fmt.Printf("%v 結(jié)構(gòu)體有%v個(gè)方法.\n", typ, num) 76 num = typ1.NumMethod() 77 fmt.Printf("%v 結(jié)構(gòu)體有%v個(gè)方法.\n", typ1, num) 78 79 // 調(diào)用結(jié)構(gòu)體的方法,并傳參數(shù) 80 var params []reflect.Value 81 // reflecttest.Monster 結(jié)構(gòu)體有0個(gè)方法. 82 params = append(params, reflect.ValueOf(1)) 83 // *reflecttest.Monster 結(jié)構(gòu)體有3個(gè)方法. 84 params = append(params, reflect.ValueOf(2)) 85 res := val1.MethodByName("GetSum").Call(params) 86 // 調(diào)用結(jié)構(gòu)體中的'GetSum()'=3 , 返回的類型是[]reflect.Value 87 fmt.Printf("調(diào)用結(jié)構(gòu)體中的'GetSum()'=%v , 返回的類型是%T\n", res[0], res) 88 89 } 90 91 // 函數(shù)適配器:給要執(zhí)行的函數(shù)加日志 92 func TestReflectFunc(function, f1 interface{}) { 93 94 funVal := reflect.ValueOf(function).Elem() 95 funTyp := funVal.Type() 96 97 packFunc := func(in []reflect.Value) (result []reflect.Value) { 98 fmt.Println("---begin---") 99 result = reflect.ValueOf(f1).Call(in) 100 fmt.Println("---end---") 101 return result 102 } 103 104 v := reflect.MakeFunc(funTyp, packFunc) 105 funVal.Set(v) 106 107 } 108 109 func TestReflect1() { 110 tfunc := func(a int, b int) int { 111 return a + b 112 } 113 114 TestReflectFunc(&tfunc, tfunc) 115 c := tfunc(1, 2) 116 fmt.Println(c) 117 118 obj := Monster{} 119 obj.SetValue("Tom", 19, 102, "Man") 120 TestStructFieldTag(&obj) 121 fmt.Println(obj) 122 }
二.單元測(cè)試
1 package main 2 3 import ( 4 "testing" 5 ) 6 7 func TestAddUpper(t *testing.T) { 8 /* 9 注意細(xì)節(jié): 10 1.測(cè)試文件名必須"_test.go"結(jié)尾.一般用測(cè)試單元文件的名加上后綴 11 2.測(cè)試用例函數(shù)必須以Test開(kāi)頭,一般用"Test+被測(cè)試的函數(shù)名" 12 3.Testddpper(t *testing.T) 的形參類型必須是"t *testing.T" 13 4.一個(gè)測(cè)試用例文件中可以有多個(gè)測(cè)試用例函數(shù) 14 5.運(yùn)行測(cè)試用例指令 15 go test // 如果運(yùn)行正確,無(wú)日志,錯(cuò)誤時(shí),會(huì)輸出日志 16 go test -v // 運(yùn)行正確錯(cuò)誤,都輸出日志 17 go test [測(cè)試單元文件名main_test.go] [測(cè)試的原文件main.go] // 測(cè)試指定的測(cè)試單元 18 go test -v -test.run [具體測(cè)試的方法TestAddUpper] // 測(cè)試具體單個(gè)方法 19 6.當(dāng)出現(xiàn)錯(cuò)誤時(shí),可以使用t.Fatalf 來(lái)格式化輸出錯(cuò)誤信息,并退出程序 20 7.t.Logf方法可以輸出相應(yīng)的日志 21 8.測(cè)試用例函數(shù),并沒(méi)有放在main函數(shù)中也執(zhí)行了,這就是測(cè)試用例的方便之處 22 9,PASS表示測(cè)試用例運(yùn)行成功,FAIL表示測(cè)試用例運(yùn)行失敗 23 24 */ 25 sum := TestUnit(10) 26 if sum != 55 { 27 t.Fatalf("TestUnit(10) 執(zhí)行錯(cuò)誤,期望值=%v,實(shí)際值=%v\n", 55, sum) 28 } 29 t.Logf("TestUnit(10) 執(zhí)行正確") 30 }

浙公網(wǎng)安備 33010602011771號(hào)