上个月给 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 @metrue 🙏
|
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 |