// TypeOf returns the reflection [Type] that represents the dynamic type of i. // If i is a nil interface value, TypeOf returns nil. funcTypeOf(i any) Type { return toType(abi.TypeOf(i)) }
// Type is the runtime representation of a Go type. // // Be careful about accessing this type at build time, as the version // of this type in the compiler/linker may not have the same layout // as the version in the target binary, due to pointer width // differences and any experiments. Use cmd/compile/internal/rttype // or the functions in compiletype.go to access this type instead. // (TODO: this admonition applies to every type in this package. // Put it in some shared location?) type Type struct { Size_ uintptr PtrBytes uintptr// number of (prefix) bytes in the type that can contain pointers Hash uint32// hash of type; avoids computation in hash tables TFlag TFlag // extra type information flags Align_ uint8// alignment of variable with this type FieldAlign_ uint8// alignment of struct field with this type Kind_ Kind // enumeration for C // function for comparing objects of this type // (ptr to object A, ptr to object B) -> ==? Equal func(unsafe.Pointer, unsafe.Pointer)bool // GCData stores the GC type data for the garbage collector. // Normally, GCData points to a bitmask that describes the // ptr/nonptr fields of the type. The bitmask will have at // least PtrBytes/ptrSize bits. // If the TFlagGCMaskOnDemand bit is set, GCData is instead a // **byte and the pointer to the bitmask is one dereference away. // The runtime will build the bitmask if needed. // (See runtime/type.go:getGCMask.) // Note: multiple types may have the same value of GCData, // including when TFlagGCMaskOnDemand is set. The types will, of course, // have the same pointer layout (but not necessarily the same size). GCData *byte Str NameOff // string form PtrToThis TypeOff // type for pointer to this type, may be zero }
// Struct field type structField = abi.StructField // 注意:你平时用的是 reflect.structField,不是reflect.StructField
// structType represents a struct type. type structType struct { abi.StructType }
func(t *rtype) Field(i int) StructField { if t.Kind() != Struct { panic("reflect: Field of non-struct type " + t.String()) } tt := (*structType)(unsafe.Pointer(t)) return tt.Field(i) }
// Field returns the i'th struct field. func(t *structType) Field(i int) (f StructField) { if i < 0 || i >= len(t.Fields) { panic("reflect: Field index out of bounds") } p := &t.Fields[i] f.Type = toType(p.Typ) f.Name = p.Name.Name() f.Anonymous = p.Embedded() if !p.Name.IsExported() { f.PkgPath = t.PkgPath.Name() } if tag := p.Name.Tag(); tag != "" { f.Tag = StructTag(tag) } f.Offset = p.Offset
// We can't safely use this optimization on js or wasi, // which do not appear to support read-only data. if i < 256 && runtime.GOOS != "js" && runtime.GOOS != "wasip1" { staticuint64s := getStaticuint64s() p := unsafe.Pointer(&(*staticuint64s)[i]) if unsafe.Sizeof(int(0)) == 4 && goarch.BigEndian { p = unsafe.Add(p, 4) } f.Index = unsafe.Slice((*int)(p), 1) } else { // NOTE(rsc): This is the only allocation in the interface // presented by a reflect.Type. It would be nice to avoid, // but we need to make sure that misbehaving clients of // reflect cannot affect other uses of reflect. // One possibility is CL 5371098, but we postponed that // ugliness until there is a demonstrated // need for the performance. This is issue 2320. f.Index = []int{i} } return }
// A StructTag is the tag string in a struct field. // // By convention, tag strings are a concatenation of // optionally space-separated key:"value" pairs. // Each key is a non-empty string consisting of non-control // characters other than space (U+0020 ' '), quote (U+0022 '"'), // and colon (U+003A ':'). Each value is quoted using U+0022 '"' // characters and Go string literal syntax. type StructTag string
// Get returns the value associated with key in the tag string. // If there is no such key in the tag, Get returns the empty string. // If the tag does not have the conventional format, the value // returned by Get is unspecified. To determine whether a tag is // explicitly set to the empty string, use [StructTag.Lookup]. func(tag StructTag) Get(key string) string { v, _ := tag.Lookup(key) return v }
// Lookup returns the value associated with key in the tag string. // If the key is present in the tag the value (which may be empty) // is returned. Otherwise the returned value will be the empty string. // The ok return value reports whether the value was explicitly set in // the tag string. If the tag does not have the conventional format, // the value returned by Lookup is unspecified. func(tag StructTag) Lookup(key string) (value string, ok bool) { // When modifying this code, also update the validateStructTag code // in cmd/vet/structtag.go.
for tag != "" { // Skip leading space. i := 0 for i < len(tag) && tag[i] == ' ' { i++ } tag = tag[i:] if tag == "" { break }
// Scan to colon. A space, a quote or a control character is a syntax error. // Strictly speaking, control chars include the range [0x7f, 0x9f], not just // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters // as it is simpler to inspect the tag's bytes than the tag's runes. i = 0 for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { i++ } if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { break } name := string(tag[:i]) tag = tag[i+1:]
// Scan quoted string to find value. i = 1 for i < len(tag) && tag[i] != '"' { if tag[i] == '\\' { i++ } i++ } if i >= len(tag) { break } qvalue := string(tag[:i+1]) tag = tag[i+1:]
if key == name { value, err := strconv.Unquote(qvalue) if err != nil { break } return value, true } } return"", false }
// GetTag 零拷贝获取Tag值 // 比 reflect.StructTag.Get 快,避免了字符串拷贝 funcGetTag(tag reflect.StructTag, key string) (value string, ok bool) { for tag != "" { // Skip leading space. i := 0 for i < len(tag) && tag[i] == ' ' { i++ } tag = tag[i:] if tag == "" { break }
// Scan to colon. A space, a quote or a control character is a syntax error. i = 0 for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { i++ } if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { break } name := string(tag[:i]) tag = tag[i+1:]
// Scan quoted string to find value. needUnquote := false i = 1 for i < len(tag) && tag[i] != '"' { if tag[i] == '\\' { needUnquote = true i++ } i++ } if i >= len(tag) { break } tmp := tag[:i+1] qvalue := string(tmp) tag = tag[i+1:]
if key == name { if needUnquote { // 需要转义时,还是得分配新字符串 value, err := strconv.Unquote(qvalue) if err != nil { break } return value, true } // 不需要转义时,直接返回字符串切片 // Go的字符串切片是零拷贝的 return qvalue[1 : len(qvalue)-1], true } } return"", false }
// 零拷贝方式:避免无意义的分配 st := zerorefl.Type2StructType(t) if st != nil { var field reflect.StructField if zerorefl.GetField(&field, st, 0) { tag2, _ := zerorefl.GetTag(field.Tag, "orm") fmt.Printf("Tag值: %s (零拷贝)\n", tag2) } }