}
}
输出:
*main.B :
{ap main func(*main.B) <func(*main.B) Value> 0}
{av main func(*main.B) <func(*main.B) Value> 1}
{bp main func(*main.B) <func(*main.B) Value> 2}
{bv main func(*main.B) <func(*main.B) Value> 3}
main.B :
{av main func(*main.B) <func(*main.B) Value> 0}
{bv main func(*main.B) <func(*main.B) Value> 1}
有一点和想象的不同,反射能探知当前包或外包的非导出结构成员。
import (
"net/http"
"reflect"
"fmt"
)
func main() {
var s http.Server
t := reflect.TypeOf(s)
for i := 0; i < t.NumField(); i++ {
fmt.Println(t.Field(i).Name)
}
}
输出:
Addr
Handler
ReadTimeout
WriteTimeout
TLSConfig
MaxHeaderBytes
TLSNextProto
ConnState
ErrorLog
disableKeepAlives
nextProtoOnce
nextProtoErr
相对 reflect 而言,当前包 和 外包 都是“外包”。
可用反射提取 struct tag,还能自动分解。其常用于 ORM 映射,或数据格式验证。
type user struct {
name string `field:"name" type:"varchar(50)"`
age int `field:"age" type:"int"`
}
func main() {
var u user
t := reflect.TypeOf(u)
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fmt.Printf("%s: %s %sn", f.Name, f.Tag.Get("field"), f.Tag.Get("type"))
}
}
输出:
name: name varchar(50)
age: age int
辅助判断方法 Implements()、ConvertibleTo、AssignableTo() 都是运行期进行 动态调用 和 赋值 所必需的。
type X int
func (X) String() string {
return ""
}
func main() {
var a X
t := reflect.TypeOf(a)
// Implements 不能直接使用类型作为参数,导致这种用法非常别扭
st := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
fmt.Println(t.Implements(st))
it := reflect.TypeOf(0)
fmt.Println(t.ConvertibleTo(it))
fmt.Println(t.AssignableTo(st), t.AssignableTo(it))
}
输出:
true
true
true false
二、值(Value)
和 Type 获取类型信息不同,Value 专注于对象实例数据读写。
在前面章节曾提到过,接口变量会复制对象,且是 unaddressable 的,所以要想修改目标对象,就必须使用指针。









