本文为原创, 遵循 CC 4.0 BY-SA 版权协议, 转载需注明出处: https://blog.csdn.net/big_cheng/article/details/131683131.
go1.19
type TS_S1 struct {
I int
}
func ts_1() {
s1 := TS_S1{1}
var s2 TS_S1 = s1
s1.I = 2
println(s1.I, s2.I) // 2 1
}
// pointer (的值, 即其存储的地址) 和pointer(变量) 本身的地址 含义不同.
// (pointer 0x0 值代表指向nil.)
func tp_1() {
var p *int = nil
fmt.Printf("%p %v %p\n", p, p, &p) // 0x0 0xc00000a028
var i = 3
p = &i
fmt.Printf("%p %v %p\n", p, p, &p) // 0xc00000e0d0 0xc00000e0d0 0xc00000a028 // (地址不变, 值变了)
}
pointer 类型可嵌套:
func tp_1b() {
i := 1
pi := &i
p := &pi
fmt.Printf("%T\n", p) // **int
}
ref/spec#Method_declarations: “the receiver. Its type must be a defined type T or a pointer to a defined type T … A receiver base type cannot be a pointer or interface type”.
type TP_PI *int
// method receiver 的base type 不能是pointer.
// (pointer 可嵌套, 但嵌套后不能再定义方法 - 为了简单.)
// func (TP_PI) M1() {}
// func (*TP_PI) M2() {}
上面2个方法定义的receiver base type 都是TP_PI - 是pointer 类型, 所以不许.
type MyInt int
func (*MyInt) M3() {}
上面receiver base type 是MyInt - 不是pointer 类型, 所以可以.
type TP_S2 struct {
I int
}
func (*TP_S2) M2() {}
func tp_4() {
var p *TP_S2
p.M2()
// println(p.I) - panic of nil
}
func ti_1() (err error) {
fmt.Printf("addr %p => nil %t\n", &err, err == nil) // addr 0xc0000422e0 => nil true
return nil
}
type TI_I1 interface {
M1()
}
// (method receiver 的base type 不能是interface.)
// func (TI_I1) M2() {}
// func (*TI_I1) M3() {}
func ti_1c() {
var i TI_I1
i.M1() // panic of nil
}
func (TS_S1) Read(p []byte) (int, error) { return len(p), nil }
func ti_2() {
s := TS_S1{1}
var r io.Reader = s
s.I = 2
s2 := r.(TS_S1)
s2.I = 3
println(s.I, (r.(TS_S1)).I, s2.I) // 2 1 3
}
// interface 内部包含一个concrete (值与类型).
// interface 赋值给interface, 实际赋的是concrete copy.
// 即concrete 不会是interface - 也即interface 不能嵌套interface.
func ti_3() {
s := TS_S1{1}
var r io.Reader = s
var i any = r // (赋的不是r, 而是其concrete copy)
s.I = 2
println(s.I, (i.(TS_S1).I)) // 2 1
fmt.Printf("%s\n", reflect.TypeOf(i)) // tmpl.TS_S1 (any 记录了concrete 的类型)
}
concrete 的值与类型:
// interface 的concrete:
//
// 值为untyped nil/interface nil 时, 没有类型.
// 值为其他nillable-typed nil 时, 有类型 - 这与reflect.TypeOf 行为一致.
func ti_4() {
var i any = nil
var r io.Reader = nil
fmt.Printf("%t %t %t\n", // true
reflect.TypeOf(i) == nil,
reflect.TypeOf(r) == nil,
reflect.TypeOf((io.Reader)(nil)) == nil,
)
fmt.Printf("%t %t %t %t/%t %t\n", // false
reflect.TypeOf((chan int)(nil)) == nil,
reflect.TypeOf((func() int)(nil)) == nil,
reflect.TypeOf((map[string]int)(nil)) == nil,
reflect.TypeOf((*int)(nil)) == nil,
reflect.TypeOf((*any)(nil)) == nil,
reflect.TypeOf(([]int)(nil)) == nil,
)
}
// Value 类似interface, 也是内部包含一个concrete (值与类型).
// 例如Value.Type() 实际是指该concrete 的类型.
func tr_1() {
v := reflect.ValueOf(2)
fmt.Printf("%s\n", v.Type()) // int
println(v.Interface().(int)) // 2
}
// Value invalid 代表从未设置过concrete.
//
// Zero(ValueType) 返回的value 设置了concrete = 另一个invalid 的value.
// 注: v.IsZero() 是针对concrete 而非v 自己.
//
// 另, 上述也表明: value 可嵌套value.
func tr_2() {
var v reflect.Value // 或 v := reflect.Value{}
fmt.Printf("valid %t\n", v.IsValid()) // (Invalid)
typ := reflect.TypeOf((*reflect.Value)(nil)).Elem()
fmt.Printf("%s\n", typ) // reflect.Value
v = reflect.Zero(typ)
// reflect.Value (struct): valid true zero true
fmt.Printf("%s (%s): valid %t zero %t\n",
v.Type(), v.Kind(), v.IsValid(), v.IsZero())
//
v = v.Interface().(reflect.Value)
fmt.Printf("%t\n", v.IsValid()) // (Invalid)
}
(重要)
// ValueOf untyped nil/interface nil 结果invalid.
//
// 对其他nillable-typed nil 结果valid - 即concrete 有类型无值(为nil).
// (注: 包括chan/func/map/pointer/slice).
func tr_3() {
// (Invalid)
println(
reflect.ValueOf(nil).IsValid(),
reflect.ValueOf((any)(nil)).IsValid(),
reflect.ValueOf((io.Reader)(nil)).IsValid(),
)
// (Valid)
v := reflect.ValueOf((map[string]int)(nil))
fmt.Printf("%t, %s\n", v.IsNil(), v.Type()) // true, map[string]int
/* 注: Zero(interface) 是返回的value 的concrete = nil interface,
和ValueOf(nil interface) 结果不同.
typ := reflect.TypeOf((*io.Reader)(nil)).Elem()
v = reflect.Zero(typ)
fmt.Printf("%t, %s\n", v.IsNil(), v.Type()) // true, io.Reader
*/
}
另,
// TypeOf 返回nil 对应 ValueOf 返回invalid.
func tr_4() {
t := reflect.TypeOf((any)(nil))
println(t == nil) // true
t = reflect.TypeOf((map[string]int)(nil))
fmt.Printf("%s\n", t) // map[string]int
}
// 可能是编译器bug: 改成用同一个变量v, 则打印 true - 不对!
func tr_elem() {
i := reflect.Value{}
v := reflect.ValueOf(&i)
v = v.Elem() // 返回的v 的concrete 对应i
v = v.Interface().(reflect.Value)
println(v.IsValid()) // false
}
(Elem() 应该总是把目标对象包装在一个Value 里返回 - 在本例里就是Value 嵌Value.)
// 如果map 包含, 返回valid Value - 其concrete 是另一个invalid Value.
func tr_mapIdx() {
m := map[string]reflect.Value{
"i1": reflect.ValueOf(1),
"foo": {},
}
vm := reflect.ValueOf(m)
v := vm.MapIndex(reflect.ValueOf("foo"))
println(v.IsValid()) // true
v = v.Interface().(reflect.Value)
println(v.IsValid()) // false
}
type TR_I1 interface {
M1()
}
type TR_MAP map[string]any
func (TR_MAP) M1() {}
func tr_map2() {
m := TR_MAP{"k1": 1}
var tr TR_I1 = m
var i any = tr // 实际赋的是m copy
m["k1"] = 2
vM := reflect.ValueOf(i)
fmt.Printf("%s\n", vM.Type()) // tmpl.TR_MAP
// vK1 的concrete 类型是any
vK1 := vM.MapIndex(reflect.ValueOf("k1"))
println(vK1.Kind().String(), vK1.Elem().Int()) // interface 2
// vK1 的concrete (any) 的concrete: int/2
i = vK1.Interface()
println(i.(int)) // 2
}
(map 赋值, 其elements 实际还是同一份 - 并未copy.)
func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value reflect.Value)
for _, cmd := range pipe.Cmds {
value = s.evalCommand(dot, cmd, value)
pipeline 由一组cmd 串联而成, 依次执行, 前一个cmd 的结果value 作为后一个cmd 的追加参数.
func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final reflect.Value) reflect.Value
cmd = arg0 arg1 arg2 …
例如: .Method1 .Key1 .Field2.Field3
arg0 如果是Field/Chain/Identifier/Pipe/Variable 节点, 则转到对应方法.
注: notAFunction 方法检查cmd 不是个方法调用: 只有arg0 且无final (== missingVal).
其他节点均不是方法调用: Bool/Dot/Nil/Number/String.
errorf 自己会panic, 后面再加panic 使意图更明确.
func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value
field = args[0].
args[1:] 和final 携带可能的其他参数, 因为field 可能是个方法如: .Method1 .Key1 123 nil.
直接转到evalFieldChain.
func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value
ChainNode = FieldNode 前加一个(非Field/Identifier/Variable) 节点 - 一般这是一个pipe 节点: (pipe).Field1.Field2. 但不做假定, 调用通用的evalArg 求值:
pipe := s.evalArg(dot, nil, chain.Node)
(注: 类型传nil - 目前不知.)
再转到evalFieldChain (以pipe 为receiver).
func (s *state) evalFieldChain(dot, receiver reflect.Value, node parse.Node, ident []string, args []parse.Node, final reflect.Value) reflect.Value
.X.Y.Z arg1 arg2 … 形式. dot 用于arg, receiver 用于chain (.X.Y.Z).
chain 的各级存储在ident, 从首个到次末个(.X, .Y) 依次调用evalField 求值. chain 的前面各级肯定没有参数, 所以传nil 和missingVal. receiver 逐次更新.
最末ident (.Z) 求值时传递args 和final.
func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value
求receiver.fieldName 的值. 可能有arg (此时fieldName 是方法名) - 用dot 求其值.
如果receiver 是pointer 或interface, 连续去掉所有的pointer 和interface 返回最里层的concrete (注: interface 不能嵌套所以应该只有一层).
阻止"calling a method on a nil interface can’t work" 情况.
首先将fieldName 当作方法名来处理.
receiver 已经dereference.
因为待调用方法可能定义在&receiver 上, 再indirect 一次(在*T 上可以同时看到T 和*T 的方法), 但也阻止"不能给interface 再定义方法" 和"A receiver base type cannot be a pointer" 2种情况.
如果能找到该方法, 转到evalCall. 否则不是方法, 往下.
不是方法时hasArgs 应该为false.
其他情况报错"can’t evaluate field …".
func (s *state) evalVariableNode(dot reflect.Value, variable *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value
$x.Field1.Field2… 形式.
取出$x 的值, 再转到evalFieldChain.
func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode)
evalPipeline 后indirect, 以防待遍历对象嵌套在Value 里面.
oneIteration:
因为evalPipeline 里已经定义了变量, 所以oneIteration 里可以直接setTopVar.
区分val 的类型: Array/Slice/Map/Chan 来遍历并调用oneIteration. 如果没有一条数据则再处理ElseList.
func isTrue(val reflect.Value) (truth, ok bool)
在模板里一个reflect.Value val 是否为真. 不支持大类UnsafePointer. 对于数值是非0, 集合(array/map/slice/string) 是长度>0, nillable-type (chan/func/pointer/interface) 是非nil, struct 总是真.
func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value
调用函数或方法fun, 名称为name - node (即args[0]) 的一部分.
首先检查fun 参数的个数(比较绕).
内置函数and/or 直接在这里完成处理. 见funcs.go, 这2个函数的参数类型是reflect.Value (即argType), 所以evalArg 求出的结果是Value 嵌套一个Value. .Interface().(reflect.Value) 取到嵌套的Value.
如果短路处理到final, final 已经有值, 只需再校验类型.
下面组装参数值数组(同样较绕).
最终调用funcs.go 的safeCall 完成函数调用.
注-unwrap: 因为Value.Call 返回[]Value, 如果被调用函数本身是返回Value, 则将返回Value 嵌套Value, unwrap 主要用在这种情况下剥离外层的Value.
func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value
检查value 可否赋给类型typ 的变量.
value Invalid 时返回Invalid、或nillable-type 的nil 值、或特殊地对struct (non-nillable) 仅支持reflect.Value 类型 - 返回Zero(ValueType) - 与后面evalArg 方法里一致.
value Valid 时, 额外自动转换:
注意后2种dereference/indirection 只做一次, 不像在方法调用时持续做(见indirect 方法), 因为实践来看在这里一次即可.
func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) reflect.Value
给出任一arg 节点n, 及其类型typ (可能nil), 求值. 有2种情况:
与evalCommand 方法较类似, 先处理可能带参数的节点类型(Field/Chain 等) 但增加类型dot/nil:
再switch typ.Kind() 处理(typ non-nil).
例如typ 大类是bool, 则evalBool 要求节点n 一定要是BoolNode.
增加any 和reflect.Value 大类的处理.
func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Value
求函数调用的参数值, 参数类型any 或reflect.Value.
与evalArg 方法相比少了ChainNode - 因为在evalArg 前半段已处理.
func indirect(v reflect.Value) (rv reflect.Value, isNil bool)
循环dereference pointer/interface, 直至其指向的或concrete 是nil.
注意: 返回的isNil false 可能不准, 例如用一个nil slice 调用也返回false. 只有返回的isNil true 才是准的.
func printableValue(v reflect.Value) (any, bool)
注-“return v.Interface()”: 如果v 嵌套interface 则返回该interface, fmt 对interface 会打印其concrete.
见evalField 方法. 如果receiver 上能找到该方法, 则会执行. 否则receiver 作为struct 拥有该方法(为field) 或作为map 拥有该方法(为elem) 都会直接返回而非执行该方法.
(ref/spec#Method_declarations: If the base type is a struct type, the non-blank method and field names must be distinct.)
例如TS_S1 类型定义Add 方法:
func (s TS_S1) Add(i ...int) int
则下面模板会执行该方法2次(.Key1 求值为TS_S1 对象):
a {{.Key1.Add .Key1.Add}} b
funcs.go addValueFuncs 方法用于添加用户自定义函数:
func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
for name, fn := range in {
......
v := reflect.ValueOf(fn)
if v.Kind() != reflect.Func { ...... }
if !goodFunc(v.Type()) { ...... }
out[name] = v
}
}
这里检查了v.Kind() 和v.Type(), 但遗漏检查v.IsNil() - 因为func 类型是nillable-type, Value concrete 可以类型是func 但值为nil.
t := template.New("P")
t.Funcs(template.FuncMap{
"foo": (func() int)(nil),
})
t.Parse("a {{call foo}} b")
上面模板可以Parse, 但执行时evalCall => safeCall => fun.Call(args) 会报错: call of nil function!