reflect包實現了運行時反射,允許程序操作任意類型的對象。典型用法是用靜態類型interface{}保存一個值,通過調用TypeOf獲取其動態類型信息,該函數返回一個Type類型值。調用ValueOf函數返回一個Value類型值,該值代表運行時的數據。Zero接受一個Type類型參數并返回一個代表該類型零值的Value類型值
type
package mainimport ("reflect""fmt"
)type lx interface {SayHi()
}type User struct {Name stringAge int64Sex string
}func (u *User) SayHi() {fmt.Println("hello world")
}func main() {user := User{"張三", 25, "男"}FillStruct(user)
}func FillStruct(obj interface{}) {t := reflect.TypeOf(obj) //反射出一個interface{}的類型fmt.Println(t.Name()) //類型名fmt.Println(t.Kind().String()) //Type類型表示的具體分類fmt.Println(t.PkgPath()) //反射對象所在的短包名fmt.Println(t.String()) //包名.類型名fmt.Println(t.Size()) //要保存一個該類型要多少個字節fmt.Println(t.Align()) //返回當從內存中申請一個該類型值時,會對齊的字節數fmt.Println(t.FieldAlign()) //返回當該類型作為結構體的字段時,會對齊的字節數var u Userfmt.Println(t.AssignableTo(reflect.TypeOf(u))) // 如果該類型的值可以直接賦值給u代表的類型,返回真fmt.Println(t.ConvertibleTo(reflect.TypeOf(u))) // 如該類型的值可以轉換為u代表的類型,返回真fmt.Println(t.NumField()) // 返回struct類型的字段數(匿名字段算作一個字段),如非結構體類型將panicfmt.Println(t.Field(0).Name) // 返回struct類型的第i個字段的類型,如非結構體或者i不在[0, NumField())內將會panicfmt.Println(t.FieldByName("Age")) // 返回該類型名為name的字段(會查找匿名字段及其子字段),布爾值說明是否找到,如非結構體將panicfmt.Println(t.FieldByIndex([]int{0})) // 返回索引序列指定的嵌套字段的類型,等價于用索引中每個值鏈式調用本方法,如非結構體將會panic
}
package mainimport ("reflect""fmt"
)type User struct {Name stringAge intSex boolPhone *stringQian float64Atest uintGroup interface{}Btest interface{}
}func (u *User) Hello() {fmt.Println("hello world 你好世界")
}func main() {a := "hello world 你好世界"user := &User{"張三", 25, true, &a, 88.8, 9, 99, nil}var obj interface{} = userv := reflect.ValueOf(obj)method := v.MethodByName("Hello") //返回v的名為Hello的方法method.Call([]reflect.Value{}) //執行反射的方法fmt.Println(v.IsValid()) //返回v是否持有值,如果v是value零值會返回假,此時v除了IsValid String Kind之外的方法都會導致panicfmt.Println(v.Kind()) //返回v持有值的分類,如果v是value零值,返回值為invalidfmt.Println(v.Type()) //返回v持有值的類型Type表示v = v.Elem() //返回持有的接口的值,或者指針的值,如果不是interface{}或指針會panic,實際上是從 *User到Uservar u Userfmt.Println(v.Convert(reflect.TypeOf(u)).FieldByName("Name")) //轉換為其他類型的值,如果無法使用標準Go轉換規則來轉換,那么panicfmt.Println(v.FieldByName("Name").CanSet()) //是否可以設置Name的值v.FieldByName("Name").SetString("把Name值修改一下") //設置v的持有值,如果v的kind不是string或者v.Canset()返回假,會panicv.FieldByName("Name").Set(reflect.ValueOf(a)) //將v的持有值修改為a的反射值,如果Canset返回假,會panicfmt.Println(v.FieldByName("Group").Elem()) //返回持有的接口的值,或者指針的值,如果不是interface{}或指針會panicfmt.Println(v.FieldByName("Phone").Elem()) //或者指針的值fmt.Println(v.FieldByName("Name").Interface()) //把Name當做interface{}值fmt.Println(v.FieldByName("Name").String()) //返回v持有的值的字符串表示,如果v的值不是string也不會panicfmt.Println(v.FieldByName("Sex").Bool()) //返回持有的布爾值,如果v的kind不是bool會panicfmt.Println(v.FieldByName("Age").Int()) //返回持有的int64,如果v的kind不是int int8-int64會panicvar x int64fmt.Println(v.FieldByName("Age").OverflowInt(x)) //如果v持有值的類型不能無一出的表示x,會返回真,如果v的kind不是int int8-int64會panicfmt.Println(v.FieldByName("Atest").Uint()) //返回v持有的無符號整數,如果v的kind不是uint uintptr uint8 uint16 uint32 uint64會panicvar x2 uint64fmt.Println(v.FieldByName("Atest").OverflowUint(x2)) //如果v持有的值的類型不能無溢出的表示x2,會返回真,如果v的kind不是uint uintptr uint8 uint16 uint32 uint64會panicfmt.Println(v.FieldByName("Qian").Float()) //返回v持有的浮點數float64,如果v的kind不是float32 float64會panicvar x3 float64fmt.Println(v.FieldByName("Qian").OverflowFloat(x3)) //如果v持有值的類型不能無溢出的表示x3,會返回真,如果v的kind不是float32 float64會panicfmt.Println(v.FieldByName("Btest").IsNil()) //如果v持有值是否為nil,如果v的值不是通道 函數 接口 映射 指針 切片之一會panicfmt.Println(v.NumField()) //返回v持有的結構體類型值的字段數,如果v的kind不是struct會panicfmt.Println(v.Field(0)) //返回結構體的第i個字段,如果v的kind不是struct或i出界會panicfmt.Println(v.FieldByIndex([]int{0})) //和上面一樣,沒明白有啥用}