上个月给 gin 提交了一个 pr,主要用的是 reflect 相关的知识。
在最好用的命令行解析库 https://github.com/guonaihong/flag (自己封的)也大量用到 reflect 让接口变的好用。
鉴于 reflect 接口是如此的难以使用,分享下常见用法
举个例子,在使用 flag 库是,只要配置下结构体,就可以解析命令行参数
package main import ( "fmt" "github.com/guonaihong/flag" _ "os" ) type TestOption struct { Int int `opt:"i, int" usage:"test int"` Int64 int64 `opt:"i64, int64" usage:"test int64"` Strings []string `opt:"s, strings" usage:"test []string"` Int64s []int64 `opt:"i64s, int64s" usage:"test []int64"` Int2 int `opt:"i2" usage:"test int2"` } func main() { option := TestOption{} flag.ParseStruct(&option) fmt.Printf("%#v\n", option) } // 运行 // go run main.go -i 3 -i64 64 -i64s 64 -i64s 1 -i64s 2 -i64s 3 -s a -s b -s c // 输出 // main.TestOption{Int:3, Int64:64, Strings:[]string{"a", "b", "c"}, Int64s:[]int64{64, 1, 2, 3}, Int2:0}
package main import ( "fmt" "reflect" ) type test2 struct { X1 int F1 float64 } type Test struct { X int F float64 test2 } func rangeStructCore(v reflect.Value) { if v.Kind() == reflect.Struct { tValue := v.Type() for i := 0; i < v.NumField(); i++ { sf := tValue.Field(i) if sf.PkgPath != "" && !sf.Anonymous { continue } if v.Field(i).Kind() == reflect.Struct { rangeStructCore(v.Field(i)) continue } fmt.Printf("sf = %v: %v, %t, %v\n", sf, sf.PkgPath, sf.Anonymous, v.Field(i)) } } } func rangeStruct(x interface{}) { rangeStructCore(reflect.ValueOf(x)) } func main() { rangeStruct(Test{X: 3, F: 4, test2: test2{X1: 5, F1: 6}}) } // 输出 // sf = {X int 0 [0] false}: , false, 3 // sf = {F float64 8 [1] false}: , false, 4 // sf = {X1 int 0 [0] false}: , false, 5 // sf = {F1 float64 8 [1] false}: , false, 6
package main import ( "fmt" "reflect" ) type Test struct { X int } func modifyValue(x interface{}) { v := reflect.ValueOf(x) if v.Kind() == reflect.Ptr { v = v.Elem() } for i := 0; i < v.NumField(); i++ { //sf := v.Type().Field(i) sv := v.Field(i) //fmt.Printf("%v#%v#%t\n", sf, sv, sv.CanAddr()) // 这里是重点 px := sv.Addr().Interface().(*int) *px = 4 } } func main() { t := Test{X: 3} fmt.Printf("before:%#v\n", t) modifyValue(&t) fmt.Printf("after:%#v\n", t) } // 输出 // before:main.Test{X:3} // after:main.Test{X:4}
// 提取类型信息到变量里 var stringSliceType = reflect.TypeOf([]string{}) var intSliceType = reflect.TypeOf([]int{}) var int32SliceType = reflect.TypeOf([]int32{}) func typeCheck(x interface{}) { // 提取 interface{}里面的类型信息 vt := reflect.ValueOf(x).Type() switch vt { case stringSliceType: fmt.Printf("[]string{}\n") case intSliceType: fmt.Printf("[]int{}\n") case int32SliceType: fmt.Printf("[]int32{}\n") default: fmt.Printf("unkown type\n") } } func main() { typeCheck([]string{}) typeCheck([]int{}) typeCheck([]int32{}) typeCheck(0) } // 输出 // []string{} // []int{} // []int32{} // unkown type
func checkPtrAndNil(x interface{}) { v := reflect.ValueOf(x) if v.Kind() == reflect.Ptr { fmt.Printf("%v is pointer\n", v.Type()) if v.IsNil() { fmt.Printf("%v is is a null pointer\n", v.Type()) return } } fmt.Printf("%v is value\n", v.Type()) } func main() { var ip *int var sp *string var i32p *int32 checkPtrAndNil(ip) checkPtrAndNil(sp) checkPtrAndNil(i32p) checkPtrAndNil(3) } // 输出 // *int is pointer // *int is is a null pointer // *string is pointer // *string is is a null pointer // *int32 is pointer // *int32 is is a null pointer // int is value
效果相当于 var t Type
package main import ( "fmt" "reflect" ) type test struct { X int Y int } func zeroValue(x interface{}) { v := reflect.Zero(reflect.ValueOf(x).Type()) fmt.Printf("%v zero (%v)\n", x, v) } func main() { zeroValue("string") zeroValue(3) zeroValue(1.1) zeroValue(test{3, 4}) } // 输出如下 // string zero () // 3 zero (0) // 1.1 zero (0) // {3 4} zero ({0 0})
package main import ( "fmt" "reflect" ) func elem(x interface{}) { v := reflect.ValueOf(x) fmt.Printf("1.value type = %v\n", v.Type()) if v.Kind() == reflect.Ptr { v = v.Elem() } fmt.Printf("2.value type = %v\n", v.Type()) } func main() { var i int var f float64 elem(&i) elem(&f) } // 输出 // 1.value type = *int // 2.value type = int // 1.value type = *float64 // 2.value type = float64
package main import ( "fmt" "reflect" ) func getInterface(x interface{}) { x1 := reflect.ValueOf(x).Interface() fmt.Printf("x %v, x1 %v\n", x, x1) } func main() { getInterface(3) } // 输出 // x 3, x1 3
![]() | 1 guonaihong OP 再分享更多关于 reflect 的知识。 |
![]() | 2 metrue 2019-06-03 12:49:09 +08:00 想看 PR |
![]() | 3 guonaihong OP |
![]() | 4 metrue 2019-06-03 13:39:10 +08:00 @guonaihong 学习了, |
![]() | 5 guonaihong OP |
6 leon0903 2019-06-03 14:59:03 +08:00 平时工作中用了一点点 Go 的反射,觉得还是不好用,至少在反射方面和 Java 相比感觉差了很多 |
![]() | 7 guonaihong OP @leon0903 是的,go 的反射确实不好用。 |
8 HsingChih 2019-07-20 16:24:32 +08:00 谢了,正好用到 |
![]() | 9 guonaihong OP 2019-08-23 13:35:02 +08:00 |