go源码阅读——value.go
Posted Wang-Junchao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go源码阅读——value.go相关的知识,希望对你有一定的参考价值。
【博文目录>>>】 【项目地址>>>】
基本内容
value文件主要提供值的一些调用方法,value所需要的值在在type.go文件中定义
package reflect
import (
"math"
"runtime"
"unsafe"
)
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
// Value is the reflection interface to a Go value.
//
// Not all methods apply to all kinds of values. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of value before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run time panic.
//
// The zero Value represents no value.
// Its IsValid method returns false, its Kind method returns Invalid,
// its String method returns "<invalid Value>", and all other methods panic.
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
//
// A Value can be used concurrently by multiple goroutines provided that
// the underlying Go value can be used concurrently for the equivalent
// direct operations.
//
// To compare two Values, compare the results of the Interface method.
// Using == on two Values does not compare the underlying values
// they represent.
/**
* Value是Go值的反射接口。
*
* 并非所有方法都适用于所有类型的值。 在每种方法的文档中都注明了限制(如果有)。
* 在调用特定于种类的方法之前,使用Kind方法找出值的种类。 调用不适合该类型的方法会导致运行时恐慌。
*
* 零值表示无值。
* 它的IsValid方法返回false,其Kind方法返回Invalid,其String方法返回"<invalid Value>",所有其他方法均会出现恐慌情况。
* 大多数函数和方法从不返回无效值。
* 如果是,则其文档会明确说明条件。
*
* 一个值可以由多个goroutine并发使用,前提是可以将基础Go值同时用于等效的直接操作。
*
* 要比较两个值,请比较Interface方法的结果。
* 在两个值上使用==不会比较它们表示的基础值。
*/
type Value struct
// typ holds the type of the value represented by a Value.
/**
* typ包含由值表示的值的类型。
*/
typ *rtype
// Pointer-valued data or, if flagIndir is set, pointer to data.
// Valid when either flagIndir is set or typ.pointers() is true.
/**
* 指针值的数据;如果设置了flagIndir,则为数据的指针。
* 在设置flagIndir或typ.pointers()为true时有效。
*/
ptr unsafe.Pointer
// flag holds metadata about the value.
// The lowest bits are flag bits:
// - flagStickyRO: obtained via unexported not embedded field, so read-only
// - flagEmbedRO: obtained via unexported embedded field, so read-only
// - flagIndir: val holds a pointer to the data
// - flagAddr: v.CanAddr is true (implies flagIndir)
// - flagMethod: v is a method value.
// The next five bits give the Kind of the value.
// This repeats typ.Kind() except for method values.
// The remaining 23+ bits give a method number for method values.
// If flag.kind() != Func, code can assume that flagMethod is unset.
// If ifaceIndir(typ), code can assume that flagIndir is set.
/**
* 标志保存有关该值的元数据。
* 最低位是标志位:
* -flagStickyRO:通过未导出的未嵌入字段获取,因此为只读
* -flagEmbedRO:通过未导出的嵌入式字段获取,因此为只读
* -flagIndir:val保存指向数据的指针
* -flagAddr:v.CanAddr为true(暗示flagIndir)
* -flagMethod:v是方法值。
* 接下来的五位给出值的种类。
* 重复typ.Kind()中的值,方法值除外。
* 其余的23+位给出方法值的方法编号。
* 如果flag.kind() != Func,则代码可以假定flagMethod未设置。
* 如果是ifaceIndir(typ),则代码可以假定设置了flagIndir。
*/
flag
// A method value represents a curried method invocation
// like r.Read for some receiver r. The typ+val+flag bits describe
// the receiver r, but the flag's Kind bits say Func (methods are
// functions), and the top bits of the flag give the method number
// in r's type's method table.
/**
* 方法值表示类似r.Read的经过当前(curried)的方法调用,用于某些接收方r。
* typ + val + flag位描述接收方r,但标志的Kind位表示Func(方法是函数),
* 并且标志的高位给出r的类型的方法表中的方法编号。
*/
type flag uintptr
/**
* flag类型是uintptr,此类型文档并未说明是多少位,只是说位数足够多,可以纳任何指针的位模式
* 为了方便解理,这里假设uintptr是uint32
* flag的位模式分成几组,从高位到底位:[31:10][9][8][7][6][5][4:0]
* [4:0]: 第0~4位:共计5位,用于表示值类型,最多可表示32种类型,值类型参见同包下的,type.go Kind枚举
* [5]: 第5位:只读类型,设置为1表示:通过未导出的未嵌入字段获取
* [6]: 第6位:只读类型,设置为1表示:通过未导出的嵌入式字段获取
* [7]: 第7位:间接指针标记,设置为1表示:Value的val属性保存指向数据的指针
* [8]: 第8位:可取址标记,设置为1表示:可取址,并且暗示flagIndir已经设置成1
* [9]: 第9位:方法标记,对于Value类型,第9位为1表示其是方法类型,
* [31:10]: 第10~31位:只对于Value是方法类型有用,用于表示第i个方法,将i<<flagMethodShift(10)位得到
*
*/
const (
flagKindWidth = 5 // there are 27 kinds // 种类的宽度,具体种类在type.go文件中
flagKindMask flag = 1<<flagKindWidth - 1 // 数据类型的掩码
flagStickyRO flag = 1 << 5 // 通过未导出的未嵌入字段获取,因此为只读
flagEmbedRO flag = 1 << 6 // 通过未导出的嵌入式字段获取,因此为只读
flagIndir flag = 1 << 7 // val保存指向数据的指针,val指的是Value中的ptr属性
flagAddr flag = 1 << 8 // v.CanAddr为true(暗示flagIndir),v指Value的实例
flagMethod flag = 1 << 9 // v是方法值,v指Value的实例
flagMethodShift = 10 // 计算是第几个方法需要的位移数
flagRO flag = flagStickyRO | flagEmbedRO // 表示是否只读
)
/**
* 求数值类型
* @return 数值类型
**/
func (f flag) kind() Kind
return Kind(f & flagKindMask)
/**
* 获取只读标记
*/
func (f flag) ro() flag
if f&flagRO != 0
return flagStickyRO
return 0
// pointer returns the underlying pointer represented by v.
// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
/**
* 指针返回v表示的底层指针。
* v.Kind()必须是Ptr,Map,Chan,Func或UnsafePointer
* @return
**/
func (v Value) pointer() unsafe.Pointer
if v.typ.size != ptrSize || !v.typ.pointers()
panic("can't call pointer on a non-pointer Value")
if v.flag&flagIndir != 0
return *(*unsafe.Pointer)(v.ptr)
return v.ptr
// packEface converts v to the empty interface.
/**
* packEface将v转换为空接口。
* @return 空接口
**/
func packEface(v Value) interface
t := v.typ
var i interface
e := (*emptyInterface)(unsafe.Pointer(&i))
// First, fill in the data portion of the interface.
// 首先,填写接口的数据部分。
switch
case ifaceIndir(t): // ifaceIndir报告t是否间接存储在接口值中。
if v.flag&flagIndir == 0
panic("bad indir")
// Value is indirect, and so is the interface we're making.
// 值是间接的,我们正在建立的接口也是间接的。
ptr := v.ptr
if v.flag&flagAddr != 0
// TODO: pass safe boolean from valueInterface so
// we don't need to copy if safe==true?
// TODO:从valueInterface传递安全布尔值,因此如果safe == true,我们不需要复制吗?
c := unsafe_New(t) // 在runtime包中实验,用于创建一个Pointer类型
typedmemmove(t, c, ptr) // typedmemmove将类型t的值从prt复制到c。
ptr = c
e.word = ptr
case v.flag&flagIndir != 0:
// Value is indirect, but interface is direct. We need
// to load the data at v.ptr into the interface data word.
// 值是间接的,但接口是直接的。 我们需要将v.ptr处的数据加载到接口数据字中。
e.word = *(*unsafe.Pointer)(v.ptr)
default:
// Value is direct, and so is the interface.
// 值是直接的,接口也是直接的。
e.word = v.ptr
// Now, fill in the type portion. We're very careful here not
// to have any operation between the e.word and e.typ assignments
// that would let the garbage collector observe the partially-built
// interface value.
// 现在,填写类型部分。 在这里,我们非常小心,不要在e.word和e.typ分配之间进行任何操作,
// 以免垃圾回收器观察部分构建的接口值。
e.typ = t
return i
// unpackEface converts the empty interface i to a Value.
/**
* unpackEface将空接口i转换为Value。
* @param 接口
* @return Value类型
**/
func unpackEface(i interface) Value
e := (*emptyInterface)(unsafe.Pointer(&i))
// NOTE: don't read e.word until we know whether it is really a pointer or not.
// 注意:在我们知道e.word是否真的是指针之前,不要读它。
t := e.typ
if t == nil // i对应的类型为空,则不需要设置相关值
return Value
f := flag(t.Kind())
if ifaceIndir(t) // 设置接口值标记
f |= flagIndir
return Valuet, e.word, f
// A ValueError occurs when a Value method is invoked on
// a Value that does not support it. Such cases are documented
// in the description of each method.
/**
* 在不支持Value的Value方法上调用Value方法时,发生ValueError。
* 在每种方法的说明中都记录了这种情况。
*/
type ValueError struct
Method string
Kind Kind
func (e *ValueError) Error() string
if e.Kind == 0
return "reflect: call of " + e.Method + " on zero Value"
return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value"
// methodName returns the name of the calling method,
// assumed to be two stack frames above.
/**
* methodName返回调用方法的名称,假定为上面有两个堆栈帧。
*/
func methodName() string
/**
* func Caller(skip int) (pc uintptr, file string, line int, ok bool)
* Caller报告有关调用goroutine堆栈上函数调用的文件和行号信息。
* 参数skip是要提升的堆栈帧数,其中0标识Caller的调用者。
*(由于历史原因,在Caller和Callers之间,跳过的含义有所不同。)
* 返回值报告相应调用文件中的程序计数器,文件名和行号。 如果该信息不可能恢复,
* 则ok布尔值为False。
*/
pc, _, _, _ := runtime.Caller(2) // Question: 为什么是2?
/**
* 给定程序计数器地址,否则为nil。
* 如果pc由于内联而表示多个函数,它将返回一个* Func描述最内部的函数,
* 但带有最外部的函数的条目。
*/
f := runtime.FuncForPC(pc)
if f == nil
return "unknown method"
return f.Name()
// emptyInterface is the header for an interface value.
/**
* emptyInterface是interface值的头部。
*/
type emptyInterface struct
typ *rtype
word unsafe.Pointer
// nonEmptyInterface is the header for an interface value with methods.
/**
* nonEmptyInterface是带有方法的接口值的头部。
*/
type nonEmptyInterface struct
// see ../runtime/iface.go:/Itab
itab *struct
ityp *rtype // static interface type // 静态接口类型
typ *rtype // dynamic concrete type // 动态创建类型
hash uint32 // copy of typ.hash // hash值
_ [4]byte // Question: 用于对齐?
fun [100000]unsafe.Pointer // method table* Question: 最多保存10W个方法?
word unsafe.Pointer
// mustBe panics if f's kind is not expected.
// Making this a method on flag instead of on Value
// (and embedding flag in Value) means that we can write
// the very clear v.mustBe(Bool) and have it compile into
// v.flag.mustBe(Bool), which will only bother to copy the
// single important word for the receiver.
/**
* 如果f的种类不是期望类型,则必须惊慌。
* 将此方法设置为基于标志而不是基于Value的方法(并在Value中嵌入flag标志)
* 意味着我们可以编写非常清晰的v.mustBe(Bool)并将其编译为v.flag.mustBe(Bool),
* 唯一麻烦是只需要为接收者复制一个重要的单词。
*/
func (f flag) mustBe(expected Kind)
// TODO(mvdan): use f.kind() again once mid-stack inlining gets better
// TODO(mvdan): mid-stack的内联变得更好后,再次使用f.kind()
// Question: mid-stack是什么?
if Kind(f&flagKindMask) != expected
panic(&ValueErrormethodName(), f.kind())
// mustBeExported panics if f records that the value was obtained using
// an unexported field.
/**
* 如果f记录了使用未导出字段获得的值,则必须惊慌。
*/
func (f flag) mustBeExported()
// Enhance: mustBeExported和mustBeExportedSlow两个方法一样,
if f == 0 || f&flagRO != 0
f.mustBeExportedSlow()
func (f flag) mustBeExportedSlow()
if f == 0
panic(&ValueErrormethodName(), Invalid)
if f&flagRO != 0
panic("reflect: " + methodName() + " using value obtained using unexported field")
// mustBeAssignable panics if f records that the value is not assignable,
// which is to say that either it was obtained using an unexported field
// or it is not addressable.
/**
* 如果f记录该值不可分配,则mustBeAssignable会发生panic,
* 这意味着它是使用未导出的字段获取的,或者它是不可寻址的。
*/
func (f flag) mustBeAssignable()
if f&flagRO != 0 || f&flagAddr == 0
f.mustBeAssignableSlow()
func (f flag) mustBeAssignableSlow()
if f == 0
panic(&ValueErrormethodName(), Invalid)
// Assignable if addressable and not read-only.
// 如果可寻址且不是只读,则可分配。
if f&flagRO != 0
panic("reflect: " + methodName() + " using value obtained using unexported field")
if f&flagAddr == 0
panic("reflect: " + methodName() + " using unaddressable value")
// Addr returns a pointer value representing the address of v.
// It panics if CanAddr() returns false.
// Addr is typically used to obtain a pointer to a struct field
// or slice element in order to call a method that requires a
// pointer receiver.
/**
* Addr返回表示v地址的指针值。
* 如果CanAddr()返回false,则会感到恐慌。
* Addr通常用于获取指向struct字段或slice元素的指针,以便调用需要指针接收器的方法。
*/
func (v Value) Addr() Value
if v.flag&flagAddr == 0
panic("reflect.Value.Addr of unaddressable value")
return Valuev.typ.ptrTo(), v.ptr, v.flag.ro() | flag(Ptr) // Ptr是指标类型的类型值
// Bool returns v's underlying value.
// It panics if v's kind is not Bool.
/**
* Bool返回v的基础值,如果v的种类不是Bool则会恐慌。
*/
func (v Value) Bool() bool
v.mustBe(Bool)
return *(*bool)(v.ptr) // 先转成bool类型指针,再取值
// Bytes returns v's underlying value.
// It panics if v's underlying value is not a slice of bytes.
/**
* 字节返回v的底层值,如果v的底层值不是字节的片段则恐慌。
*/
func (v Value) Bytes() []byte
v.mustBe(Slice)
if v.typ.Elem().Kind() != Uint8
panic("reflect.Value.Bytes of non-byte slice")
// Slice is always bigger than a word; assume flagIndir.
// 切片总是比字(word)大; 假设flagIndir已经被设置值。
return *(*[]byte)(v.ptr)
// runes returns v's underlying value.
// It panics if v's underlying value is not a slice of runes (int32s).
/**
* runes返回v的底层值。如果v的底层值不是一小段符文(int32s),它将惊慌。
* @param
* @return
**/
func (v Value) runes() []rune
v.mustBe(Slice)
if v.typ.Elem().Kind() != Int32
panic("reflect.Value.Bytes of non-rune slice")
// Slice is always bigger than a word; assume flagIndir.
return *(*[]rune)(v.ptr)
// CanAddr reports whether the value's address can be obtained with Addr.
// Such values are called addressable. A value is addressable if it is
// an element of a slice, an element of an addressable array,
// a field of an addressable struct, or the result of dereferencing a pointer.
// If CanAddr returns false, calling Addr will panic.
/**
* CanAddr报告是否可以通过Addr获取值的地址。
* 这样的值称为可寻址的。 如果值是切片的元素,可寻址数组的元素,可寻址结构的字段或取消引用指针的结果,则该值是可寻址的。
* 如果CanAddr返回false,则调用Addr会引起恐慌。
**/
func (v Value) CanAddr() bool
return v.flag&flagAddr != 0
// CanSet reports whether the value of v can be changed.
// A Value can be changed only if it is addressable and was not
// obtained by the use of unexported struct fields.
// If CanSet returns false, calling Set or any type-specific
// setter (e.g., SetBool, SetInt) will panic.
/**
* CanSet报告v的值是否可以更改。
* 仅当值是可寻址的并且不是通过使用未导出的结构字段获得的,才可以更改它。
* 如果CanSet返回false,则调用Set或任何特定于类型的setter(例如SetBool,SetInt)都会引起恐慌。
* @param
* @return
**/
func (v Value) CanSet() bool
return v.flag&(flagAddr|flagRO) == flagAddr
// Call calls the function v with the input arguments in.
// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]).
// Call panics if v's Kind is not Func.
// It returns the output results as Values.
// As in Go, each input argument must be assignable to the
// type of the function's corresponding input parameter.
// If v is a variadic function, Call creates the variadic slice parameter
// itself, copying in the corresponding values.
/**
* Call使用输入参数调用函数v。
* 例如,如果len(in)== 3,则v.Call(in)表示Go调用v(in[0], in[1], in[2])。
* 如果v的Kind不是Func,则Call方法引起恐慌。
* 将输出结果作为Value切片返回。
* 和Go一样,每个输入参数必须可分配给函数相应输入参数的类型。
* 如果v是可变参数函数,则Call会自己创建可变参数切片参数,并复制相应的值。
* @param
* @return
**/
func (v Value) Call(in []Value) []Value
v.mustBe(Func)
v.mustBeExported()
return v.call("Call", in)
// CallSlice calls the variadic function v with the input arguments in,
// assigning the slice in[len(in)-1] to v's final variadic argument.
// For example, if len(in) == 3, v.CallSlice(in) represents the Go call v(in[0], in[1], in[2]...).
// CallSlice panics if v's Kind is not Func or if v is not variadic.
// It returns the output results as Values.
// As in Go, each input argument must be assignable to the
// type of the function's corresponding input parameter.
/**
* CallSlice使用输入参数in调用可变参数函数v,将切片in [len(in)-1]分配给v的最终可变参数。
* 例如,如果len(in) == 3,则v.CallSlice(in)表示Go调用v(in [0],in [1],in [2] ...)。
* 如果v的Kind不是Func或v不是可变参数,则CallSlice会慌张。
* 将输出结果作为Value切片返回。
* 和Go一样,每个输入参数必须可分配给函数相应输入参数的类型。
* @param
* @return
**/
func (v Value) CallSlice(in []Value) []Value
v.mustBe(Func)
v.mustBeExported()
return v.call("CallSlice", in)
var callGC bool // for testing; see TestCallMethodJump
/**
* 真正的方法调用在这里
* @param
* @return
**/
func (v Value) call(op string, in []Value) []Value
// Get function pointer, type.
t := (*funcType)(unsafe.Pointer(v.typ))
var (
fn unsafe.Pointer
rcvr Value
rcvrtype *rtype
)
if v.flag&flagMethod != 0 // v是方法的接收者
rcvr = v
rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
else if v.flag&flagIndir != 0 // 有间接指针
fn = *(*unsafe.Pointer)(v.ptr)
else
fn = v.ptr
if fn == nil
panic("reflect.Value.Call: call of nil function")
isSlice := op == "CallSlice"
n := t.NumIn()
if isSlice // CallSlice方法
if !t.IsVariadic() // 必须要有可变参数
panic("reflect: CallSlice of non-variadic function")
if len(in) < n // 参数不足
panic("reflect: CallSlice with too few input arguments")
if len(in) > n // 参数过多
panic("reflect: CallSlice with too many input arguments")
else
if t.IsVariadic() // 有可变参数
n--
if len(in) < n
panic("reflect: Call with too few input arguments")
if !t.IsVariadic() && len(in) > n
panicgo源码阅读——chan.go