针对Go SDK 1.16.6
1. 反射
1.1. Type
Type:src/reflect/type.go:38
type Type interface {
Align() int
FieldAlign() int
Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
Name() string
...
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
Elem() Type
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
FieldByNameFunc(match func(string) bool) (StructField, bool)
}
优化小技巧:内存对齐,巧妙的排列结构体的字段顺序,可以有效节省对象占用的内存大小
type Part1 struct {
a bool
b int32
c int8
d int64
e byte
}
type Part2 struct {
e byte
c int8
a bool
b int32
d int64
}
func main() {
part1 := Part1{}
part2 := Part2{}
fmt.Printf("part1 size: %d, align: %d\n", unsafe.Sizeof(part1), unsafe.Alignof(part1))
fmt.Printf("part2 size: %d, align: %d\n", unsafe.Sizeof(part2), unsafe.Alignof(part2))
}
// 输出
//part1 size: 32, align: 8
//part2 size: 16, align: 8
Type本身是可比较的
type A struct {
b bool
Name int64
Grade int
}
func main() {
a1 := new(A)
a2 := new(A)
mp := make(map[reflect.Type]int)
mp[reflect.TypeOf(a1)] = 1
fmt.Println(mp)
mp[reflect.TypeOf(a2)] = 2
fmt.Println(mp)
}
// 输出
//map[*reflect_study.A:1]
//map[*reflect_study.A:2]
1.2. Value
type Value struct {
}
1.3. Kind
// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
type Kind uint
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
)
1.4. 三大法则
- 从
interface{}
变量可以反射出反射对象;
- 从反射对象可以获取
interface{}
变量;
- 要修改反射对象,其值必须可设置;
通过TypeOf和ValueOf获取反射对象
func main() {
str := "abcd"
fmt.Println(reflect.TypeOf(str))
fmt.Println(reflect.ValueOf(str))
}
反射对象转化为interface{}
func main() {
v := reflect.ValueOf(1)
i := v.Interface().(int)
fmt.Println(i)
}

要修改反射对象,其值必须可修改
func main() {
//i := 1
//v:=reflect.ValueOf(i)
// 报错,原因:go都是值传递,反射对象v和基本类型i没有关系,所以修改反射对象v的值对基本类型i无影响,程序为了防止错误就会崩溃
//v.SetInt(2222)
//fmt.Println(i)
i := 1
v := reflect.ValueOf(&i)
v.Elem().SetInt(100)
fmt.Println(i)
}
1.5. 实现方式
type TestHandler struct {
}
func (t *TestHandler) Error() string {
panic("implement me")
}
func main() {
testError := reflect.TypeOf((*error)(nil)).Elem()
test := reflect.TypeOf(TestHandler{})
testPtr := reflect.TypeOf(&TestHandler{})
println(test.Implements(testError))
println(testPtr.Implements(testError))
}
Implements源码实现细节
接口的方法和实现类的方法进行比对,复杂度O(n)
func (t *rtype) Implements(u Type) bool {
if u == nil {
panic("reflect: nil type passed to Type.Implements")
}
if u.Kind() != Interface {
panic("reflect: non-interface type passed to Type.Implements")
}
return implements(u.(*rtype), t)
}
func implements(T, V *rtype) bool {
if T.Kind() != Interface {
return false
}
t := (*interfaceType)(unsafe.Pointer(T))
if len(t.methods) == 0 {
return true
}
if V.Kind() == Interface {
v := (*interfaceType)(unsafe.Pointer(V))
i := 0
for j := 0; j < len(v.methods); j++ {
tm := &t.methods[i]
tmName := t.nameOff(tm.name)
vm := &v.methods[j]
vmName := V.nameOff(vm.name)
if vmName.name() == tmName.name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
if !tmName.isExported() {
tmPkgPath := tmName.pkgPath()
if tmPkgPath == "" {
tmPkgPath = t.pkgPath.name()
}
vmPkgPath := vmName.pkgPath()
if vmPkgPath == "" {
vmPkgPath = v.pkgPath.name()
}
if tmPkgPath != vmPkgPath {
continue
}
}
if i++; i >= len(t.methods) {
return true
}
}
}
return false
}
......
}
1.6. 调用函数
样例:使用反射调用函数
func Add(a, b int) int {
return a + b
}
func main() {
v := reflect.ValueOf(Add)
if v.Kind() != reflect.Func {
return
}
t := v.Type()
argv := make([]reflect.Value, t.NumIn())
for i := range argv {
if t.In(i).Kind() != reflect.Int {
return
}
argv[i] = reflect.ValueOf(i)
}
result := v.Call(argv)
if len(result) != 0 && result[0].Kind() != reflect.Int {
return
}
println(result[0].Int())
}
1.7. 参考文献
Go语言设计与实现 反射
在 Go 中恰到好处的内存对齐