两个重要类型
- reflect.Type(reflect.Typeof()获得)
- reflect.Value(reflect.Value()获得)
Type的一些方法
- String
- Name 都以字符串的形式返回结构名,只是Name包括包名
- Field(index) 根据索引获得字段,返回的是StructField(字段也有类型,当然包含一个reflect.Type的字段)
- NumField 返回的结构的字段数
- FieldByName 根据字段名获得字段
带Field的方法是获取结构体字段信息的。
type Foo struct { X string Y int } func main() { var q = Foo{} var f interface{} = q t := reflect.TypeOf(f) for i := 0; i < t.NumField(); i++ { field := t.Field(i) fmt.Println(field.Name, field.Type.Name())// output: X Y string int } fi, _ := t.FieldByName("Y") fmt.Println(fi.Name) output: Y }
结构体不光有字段,还有方法,所以Go也提供了Method的一系列函数
– NumMethod
– Method
– FieldByNameFunc
Kind方法 返回对象的基本类型,如果是个结构体就返回struct。
有如下基本返回值
const ( Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )
大体可以这样使用
func main() { var q = []int{
1, 2, 3, 4} f := reflect.ValueOf(q) if f.Kind() == reflect.Slice { if fv, ok := f.Interface().([]int); ok { fmt.Println(fv) } } }
Value的一些方法
Value更关注的是接口值,而不是类型的值
- Field 返回的仍是一个Value
- Interface 获得接口值,+ 断言进行类型转换
- NumField 同上Type
func main() { var q = Foo{
"1234", 123} var f interface{
} = q t := reflect.ValueOf(f) for i := 0; i < t.NumField(); i++ { field := t.Field(i) fmt.Println(field.Interface()) } field := t.Field(0) v, _ := field.Interface().(string) fmt.Println(v) }
可以看到Value和Type有类似的地方
但我们有对改变Value的需求,很少有改变Type的需求。所以Value会有跟多的方法
一系列Set操作
- Set
- SetString
- SetBytes
- SetInt
- …
但是没有提供SetSlice >_<!
func main() { var q = Foo{
"1234", 123} var f interface{
} = &q reflect.ValueOf(f).Elem().Field(0).SetString("4321") fmt.Println(q)// output:{4321 123} }
练习:怎么给slice加一个Insert方法呢?而不用丑陋的两次append….
解答 func Insert(slice interface{}, pos int, value interface{}) interface{} { v := reflect.ValueOf(slice) ne := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(value)), 1, 1) ne.Index(0).Set(reflect.ValueOf(value)) v = reflect.AppendSlice(v.Slice(0, pos), reflect.AppendSlice(ne, v.Slice(pos, v.Len()))) return v.Interface() } func main() { slice := []int{
1, 2} fmt.Println(Insert(slice, 1, 99)) slice2 := []string{
"a", "c", "d"} slice2 = Insert(slice2, 0, "b").([]string) fmt.Println(Insert(slice2, 4, "e")) }
做下性能测试:
func Insert(slice interface{}, pos int, value interface{}) interface{} { v := reflect.ValueOf(slice) ne := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(value)), 1, 1) ne.Index(0).Set(reflect.ValueOf(value)) v = reflect.AppendSlice(v.Slice(0, pos), reflect.AppendSlice(ne, v.Slice(pos, v.Len()))) return v.Interface() } func main() { slice := []int{} slice2 := []int{} t0 := time.Now() for i := 1; i < 10000; i++ { slice = append(slice[:0], append([]int{i}, slice[0:]...)...) } t1 := time.Now() for i := 1; i < 10000; i++ { slice2 = Insert(slice2, 0, i).([]int) } t2 := time.Now() fmt.Println(t2.Sub(t1), t1.Sub(t0)) }
输出:
215.ms 138.ms
连续插入一万个,使用反射和不使用消耗时间差了一倍。但我觉得还是可以接受的。>_<….对于性能要求不高的的地方,用用反射也没什么不可啊!
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232547.html原文链接:https://javaforall.net
