上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
reflect 1.18
反射可在运行期 动态 获取类型(type)和值(value)信息。
- 代码繁琐,可读性差。
- 性能较差,不及 Unsafe 指针。
func TypeOf(i any) Type func ValueOf(i any) Value
类型(Type)表示具体的静态类型,而类别(Kind)则表示其底层结构。
相比 Type,Value 更倾向于对值的处理。两者有许多同名方法,但返回值可能不同。
package main import ( . "reflect" ) func main() { type X int var x X = 1 v := ValueOf(x) t := v.Type() println(t.PkgPath() + "." + t.Name()) // main.X switch v.Kind() { case Int: println(v.Int()) // 1 case String: println(v.String()) } // ------------------------------------- var y int = 2 ty := TypeOf(y) println(t == ty) // false println(t.Kind() == ty.Kind()) // true }
如果是 nil
接口,那么无法反射。
因为接口须和实现类型结合,才能有完整 itab
信息。
func main() { type Xer interface { A() B() } var i Xer t := TypeOf(i) println(t != nil) // false v := ValueOf(i) println(v.IsValid()) // false // println(v.Type()) // panic! // ------------------------------- // 注意,参数是指针而非接口。 t = TypeOf((*Xer)(nil)) println(t != nil) // true println(t.Elem().Name()) // Xer }
func main() { var i interface{} = (*int)(nil) t := TypeOf(i) println(t != nil) // true v := ValueOf(i) println(v.IsValid()) // true println(v.Type()) // ok! }
某些方法返回的是零值,需要进行验证。
IsValid
:验证 Value 自身是否为零值(zero Value)。IsZero
、IsNil
:验证目标对象(zero/nil value)。
func main() { // zero Value ---------------------- var v Value println(v.IsValid()) // false // println(v.IsZero()) // panic! // println(v.IsNil()) // panic! // zero value ---------------------- v = ValueOf([]int{}) println(v.IsValid()) // true println(v.IsZero()) // false var i interface{} = (*int)(nil) v = ValueOf(i) println(v.IsValid()) // true println(v.IsNil()) // true }
复合类型
除通过实例反射外,还可直接构造一些复合类型。
package main import ( "fmt" . "reflect" ) func main() { tByte := TypeOf(byte(0)) tInt := TypeOf(0) tString := TypeOf("") tSlice := TypeOf([]int{}) // -------------------------------- a := ArrayOf(10, tByte) // [10]uint8 c := ChanOf(BothDir, tInt) // chan int m := MapOf(tString, tInt) // map[string]int s := SliceOf(tInt) // []int p := PointerTo(tInt) // *int // x := StructOf(...) // --------------------------------- in := []Type{ tInt, tInt, tSlice } out := []Type{ tString } f := FuncOf(in, out, true) // func(int, int, ...int) string fmt.Println(a, c, m, s, p, f) }
另外,值和指针不是同一类型。
方法 Elem
返回指针、数组、切片、字典或通道的基类型。
func main() { x := 100 t, p := TypeOf(x), TypeOf(&x) fmt.Println(t, p, t == p) // int *int false fmt.Println(t.Kind(), p.Kind()) // int ptr fmt.Println(t == p.Elem()) // true }
func main() { x := 100 p := TypeOf(&x) s := TypeOf([]int32{}) m := TypeOf(map[string]int{}) fmt.Println(p.Elem()) // int fmt.Println(s.Elem()) // int32 fmt.Println(m.Key()) // string fmt.Println(m.Elem()) // int }
结构体
遍历结构体字段,包括 匿名嵌入 (anonymous embed)和 非导出 (unexported)字段。
type U struct { name string age int } type M struct { U title string } // ----------------------------------- func pp(t Type, prefix string) { for i := 0; i < t.NumField(); i++ { f := t.Field(i) fmt.Println(prefix, f.Name) if f.Anonymous { pp(f.Type, prefix + " ") } } } // ----------------------------------- func main() { var m M t := TypeOf(&m) if t.Kind() == Ptr { t = t.Elem() } pp(t, "") } /* U name age title */
可按多级索引查找。
只是 FieldByName
不支持多级名称。
type U struct { name string // 0 age int // 1 } type M struct { U // 0 title string // 1 } // ---------------------------------- func main() { var m M t := TypeOf(m) // 按名称查找。 name, _ := t.FieldByName("name") fmt.Println(name.Name, name.Offset) // name 0 // 按多级索引查找。 age := t.FieldByIndex([]int{0, 1}) fmt.Println(age.Name, age.Offset) // age 16 }
提取 tag,自动分解。
type User struct { id int `field:"uid" type:"int"` name string `field:"username" type:"varchar(50)"` } // ----------------------- func main() { var u User t := TypeOf(u) for i := 0; i < t.NumField(); i++ { f := t.Field(i) fmt.Println(f.Name, f.Tag.Get("field"), f.Tag.Get("type")) } } /* id: uid int name: username varchar(50) */
方法集
获取 方法集 (method set)内 导出 (exported)方法。
type N int func (N) X() {} func (*N) Y() {} // ----------------------- type M struct { N } func (M) A() {} func (*M) b() {} func (*M) C() {} // ----------------------- func main() { t := TypeOf((*M)(nil)) for i := 0; i < t.NumMethod(); i++ { fmt.Println(t.Method(i)) } if m, ok := t.MethodByName("C"); ok { fmt.Println(m) } } /* {A func(*main.M) <func(*main.M) Value> 0} {C func(*main.M) <func(*main.M) Value> 1} {X func(*main.M) <func(*main.M) Value> 2} {Y func(*main.M) <func(*main.M) Value> 3} {C func(*main.M) <func(*main.M) Value> 1} */
在官方文档里,有句让人费解的话。
type Type interface { // counts unexported methods only for interface types. NumMethod() int }
func main() { var i interface { A() b() C() } // 传入的是指针(*i),而非接口(i)。 // 通过 Elem 获取接口声明的方法。 // t := TypeOf(&i) // 0 t := TypeOf(&i).Elem() // 3 for i := 0; i < t.NumMethod(); i++ { fmt.Println(t.Method(i)) } } /* {A func() <invalid Value> 0} {C func() <invalid Value> 1} {b func() <invalid Value> 2} */
接口
围绕接口的辅助方法,作一些必要判断。
func main() { a := 100 v := ValueOf(&a) if t := TypeOf((*int)(nil)); v.Type().ConvertibleTo(t) { if p, ok := v.Interface().(*int); ok { *p += 100 fmt.Println(*p, a) // 200 200 } } }
type X int func (X) String() string { return "" } func main() { var x X t := TypeOf(x) st := TypeOf((*fmt.Stringer)(nil)).Elem() fmt.Println(t.Implements(st)) // true fmt.Println(t.AssignableTo(st)) // true }
func main() { a := 100 // 反射参数是接口(any)。 // 所以 iface.data 不能寻址和修改。 // 除非传入指针,则原对象(v.Elem)可改。 v := ValueOf(a) p := ValueOf(&a) // iface.data fmt.Println(v.CanAddr(), v.CanSet()) // false false fmt.Println(p.CanAddr(), p.CanSet()) // false false // ---------------------------------- // *data e := p.Elem() fmt.Println(e.CanAddr(), e.CanSet()) // true true if e.CanSet() { e.SetInt(200) fmt.Println(a) // 200 } if e.CanAddr() { *(*int)(unsafe.Pointer(e.UnsafeAddr())) = 300 fmt.Println(a) // 300 } }
调用
动态方法调用。
type X int func (x X) Add(y int) int { return int(x) + y } func (x X) Print(format string, y ...any) { fmt.Printf(format, y...) } // ------------------------------- func main() { var x X = 100 v := ValueOf(&x) func() { m := v.MethodByName("Add") in := []Value{ ValueOf(1) } out := m.Call(in) for _, v := range out { fmt.Println(v) } }() // 变参 func() { m := v.MethodByName("Print") in := []Value{ ValueOf("%d,%d,%d\n"), ValueOf([]any{ 1, 2, 3 }), } out := m.CallSlice(in) for _, v := range out { fmt.Println(v) } }() }
创建
创建对象实例(分配内存),对应 new
、 make
内置函数。
func main() { // --- New ------------------------- v := New(TypeOf(0)) // new(int) v.Elem().SetInt(100) fmt.Println(v.Elem().Int()) // 100 // --- NewAt ------------------------ p := new(int) v = NewAt(TypeOf(0), unsafe.Pointer(p)) v.Elem().SetInt(200) fmt.Println(v.Elem().Int(), *p) // 200 200 // --- Make ------------------------- v = MakeSlice(TypeOf([]int{}), 0, 10) v = Append(v, ValueOf(1), ValueOf(2)) fmt.Println(v) // [1, 2] // MakeMap, MakeMapWithSize, MakeChan }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论