Source File
value.go
Belonging Package
internal/reflectlite
// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package reflectliteimport ()// 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.type Value struct {// typ holds the type of the value represented by a Value.typ *abi.Type// Pointer-valued data or, if flagIndir is set, pointer to data.// Valid when either flagIndir is set or typ.pointers() is 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)// Value cannot represent method values.// 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.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.}type flag uintptrconst (flagKindWidth = 5 // there are 27 kindsflagKindMask flag = 1<<flagKindWidth - 1flagStickyRO flag = 1 << 5flagEmbedRO flag = 1 << 6flagIndir flag = 1 << 7flagAddr flag = 1 << 8flagMethod flag = 1 << 9flagMethodShift = 10flagRO flag = flagStickyRO | flagEmbedRO)func ( flag) () Kind {return Kind( & flagKindMask)}func ( flag) () flag {if &flagRO != 0 {return flagStickyRO}return 0}// pointer returns the underlying pointer represented by v.// v.Kind() must be Pointer, Map, Chan, Func, or UnsafePointerfunc ( Value) () unsafe.Pointer {if .typ.Size() != goarch.PtrSize || !.typ.Pointers() {panic("can't call pointer on a non-pointer Value")}if .flag&flagIndir != 0 {return *(*unsafe.Pointer)(.ptr)}return .ptr}// packEface converts v to the empty interface.func packEface( Value) any {:= .typvar any:= (*emptyInterface)(unsafe.Pointer(&))// First, fill in the data portion of the interface.switch {case ifaceIndir():if .flag&flagIndir == 0 {panic("bad indir")}// Value is indirect, and so is the interface we're making.:= .ptrif .flag&flagAddr != 0 {// TODO: pass safe boolean from valueInterface so// we don't need to copy if safe==true?:= unsafe_New()typedmemmove(, , )=}.word =case .flag&flagIndir != 0:// Value is indirect, but interface is direct. We need// to load the data at v.ptr into the interface data word..word = *(*unsafe.Pointer)(.ptr)default:// Value is direct, and so is the interface..word = .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..typ =return}// unpackEface converts the empty interface i to a Value.func unpackEface( any) Value {:= (*emptyInterface)(unsafe.Pointer(&))// NOTE: don't read e.word until we know whether it is really a pointer or not.:= .typif == nil {return Value{}}:= flag(.Kind())if ifaceIndir() {|= flagIndir}return Value{, .word, }}// 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.type ValueError struct {Method stringKind Kind}func ( *ValueError) () string {if .Kind == 0 {return "reflect: call of " + .Method + " on zero Value"}return "reflect: call of " + .Method + " on " + .Kind.String() + " Value"}// methodName returns the name of the calling method,// assumed to be two stack frames above.func methodName() string {, , , := runtime.Caller(2):= runtime.FuncForPC()if == nil {return "unknown method"}return .Name()}// emptyInterface is the header for an interface{} value.type emptyInterface struct {typ *abi.Typeword unsafe.Pointer}// mustBeExported panics if f records that the value was obtained using// an unexported field.func ( flag) () {if == 0 {panic(&ValueError{methodName(), 0})}if &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.func ( flag) () {if == 0 {panic(&ValueError{methodName(), abi.Invalid})}// Assignable if addressable and not read-only.if &flagRO != 0 {panic("reflect: " + methodName() + " using value obtained using unexported field")}if &flagAddr == 0 {panic("reflect: " + methodName() + " using unaddressable value")}}// 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.func ( Value) () bool {return .flag&(flagAddr|flagRO) == flagAddr}// Elem returns the value that the interface v contains// or that the pointer v points to.// It panics if v's Kind is not Interface or Pointer.// It returns the zero Value if v is nil.func ( Value) () Value {:= .kind()switch {case abi.Interface:var anyif .typ.NumMethod() == 0 {= *(*any)(.ptr)} else {= (any)(*(*interface {()})(.ptr))}:= unpackEface()if .flag != 0 {.flag |= .flag.ro()}returncase abi.Pointer::= .ptrif .flag&flagIndir != 0 {= *(*unsafe.Pointer)()}// The returned value's address is v's value.if == nil {return Value{}}:= (*ptrType)(unsafe.Pointer(.typ)):= .Elem:= .flag&flagRO | flagIndir | flagAddr|= flag(.Kind())return Value{, , }}panic(&ValueError{"reflectlite.Value.Elem", .kind()})}func valueInterface( Value) any {if .flag == 0 {panic(&ValueError{"reflectlite.Value.Interface", 0})}if .kind() == abi.Interface {// Special case: return the element inside the interface.// Empty interface has one layout, all interfaces with// methods have a second layout.if .numMethod() == 0 {return *(*any)(.ptr)}return *(*interface {()})(.ptr)}// TODO: pass safe to packEface so we don't need to copy if safe==true?return packEface()}// IsNil reports whether its argument v is nil. The argument must be// a chan, func, interface, map, pointer, or slice value; if it is// not, IsNil panics. Note that IsNil is not always equivalent to a// regular comparison with nil in Go. For example, if v was created// by calling ValueOf with an uninitialized interface variable i,// i==nil will be true but v.IsNil will panic as v will be the zero// Value.func ( Value) () bool {:= .kind()switch {case abi.Chan, abi.Func, abi.Map, abi.Pointer, abi.UnsafePointer:// if v.flag&flagMethod != 0 {// return false// }:= .ptrif .flag&flagIndir != 0 {= *(*unsafe.Pointer)()}return == nilcase abi.Interface, abi.Slice:// Both interface and slice are nil if first word is 0.// Both are always bigger than a word; assume flagIndir.return *(*unsafe.Pointer)(.ptr) == nil}panic(&ValueError{"reflectlite.Value.IsNil", .kind()})}// IsValid reports whether v represents a value.// It returns false if v is the zero Value.// If IsValid returns false, all other methods except String panic.// Most functions and methods never return an invalid Value.// If one does, its documentation states the conditions explicitly.func ( Value) () bool {return .flag != 0}// Kind returns v's Kind.// If v is the zero Value (IsValid returns false), Kind returns Invalid.func ( Value) () Kind {return .kind()}// implemented in runtime:func chanlen(unsafe.Pointer) intfunc maplen(unsafe.Pointer) int// Len returns v's length.// It panics if v's Kind is not Array, Chan, Map, Slice, or String.func ( Value) () int {:= .kind()switch {case abi.Array::= (*arrayType)(unsafe.Pointer(.typ))return int(.Len)case abi.Chan:return chanlen(.pointer())case abi.Map:return maplen(.pointer())case abi.Slice:// Slice is bigger than a word; assume flagIndir.return (*unsafeheader.Slice)(.ptr).Lencase abi.String:// String is bigger than a word; assume flagIndir.return (*unsafeheader.String)(.ptr).Len}panic(&ValueError{"reflect.Value.Len", .kind()})}// NumMethod returns the number of exported methods in the value's method set.func ( Value) () int {if .typ == nil {panic(&ValueError{"reflectlite.Value.NumMethod", abi.Invalid})}return .typ.NumMethod()}// Set assigns x to the value v.// It panics if CanSet returns false.// As in Go, x's value must be assignable to v's type.func ( Value) ( Value) {.mustBeAssignable().mustBeExported() // do not let unexported x leakvar unsafe.Pointerif .kind() == abi.Interface {= .ptr}= .assignTo("reflectlite.Set", .typ, )if .flag&flagIndir != 0 {typedmemmove(.typ, .ptr, .ptr)} else {*(*unsafe.Pointer)(.ptr) = .ptr}}// Type returns v's type.func ( Value) () Type {:= .flagif == 0 {panic(&ValueError{"reflectlite.Value.Type", abi.Invalid})}// Method values not supported.return toRType(.typ)}/** constructors*/// implemented in package runtimefunc unsafe_New(*abi.Type) unsafe.Pointer// ValueOf returns a new Value initialized to the concrete value// stored in the interface i. ValueOf(nil) returns the zero Value.func ( any) Value {if == nil {return Value{}}// TODO: Maybe allow contents of a Value to live on the stack.// For now we make the contents always escape to the heap. It// makes life easier in a few places (see chanrecv/mapassign// comment below).escapes()return unpackEface()}// assignTo returns a value v that can be assigned directly to typ.// It panics if v is not assignable to typ.// For a conversion to an interface type, target is a suggested scratch space to use.func ( Value) ( string, *abi.Type, unsafe.Pointer) Value {// if v.flag&flagMethod != 0 {// v = makeMethodValue(context, v)// }switch {case directlyAssignable(, .typ):// Overwrite type so that they match.// Same memory layout, so no harm done.:= .flag&(flagAddr|flagIndir) | .flag.ro()|= flag(.Kind())return Value{, .ptr, }case implements(, .typ):if == nil {= unsafe_New()}if .Kind() == abi.Interface && .IsNil() {// A nil ReadWriter passed to nil Reader is OK,// but using ifaceE2I below will panic.// Avoid the panic by returning a nil dst (e.g., Reader) explicitly.return Value{, nil, flag(abi.Interface)}}:= valueInterface()if .NumMethod() == 0 {*(*any)() =} else {ifaceE2I(, , )}return Value{, , flagIndir | flag(abi.Interface)}}// Failed.panic( + ": value of type " + toRType(.typ).String() + " is not assignable to type " + toRType().String())}// arrayAt returns the i-th element of p,// an array whose elements are eltSize bytes wide.// The array pointed at by p must have at least i+1 elements:// it is invalid (but impossible to check here) to pass i >= len,// because then the result will point outside the array.// whySafe must explain why i < len. (Passing "i < len" is fine;// the benefit is to surface this assumption at the call site.)func arrayAt( unsafe.Pointer, int, uintptr, string) unsafe.Pointer {return add(, uintptr()*, "i < len")}func ifaceE2I( *abi.Type, any, unsafe.Pointer)// typedmemmove copies a value of type t to dst from src.////go:noescapefunc typedmemmove( *abi.Type, , unsafe.Pointer)// Dummy annotation marking that the value x escapes,// for use in cases where the reflect code is so clever that// the compiler cannot follow.func escapes( any) {if dummy.b {dummy.x =}}var dummy struct {b boolx any}
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |