Source File
visiblefields.go
Belonging Package
reflect
// Copyright 2021 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 reflect
// VisibleFields returns all the visible fields in t, which must be a
// struct type. A field is defined as visible if it's accessible
// directly with a FieldByName call. The returned fields include fields
// inside anonymous struct members and unexported fields. They follow
// the same order found in the struct, with anonymous fields followed
// immediately by their promoted fields.
//
// For each element e of the returned slice, the corresponding field
// can be retrieved from a value v of type t by calling v.FieldByIndex(e.Index).
func ( Type) []StructField {
if == nil {
panic("reflect: VisibleFields(nil)")
}
if .Kind() != Struct {
panic("reflect.VisibleFields of non-struct type")
}
:= &visibleFieldsWalker{
byName: make(map[string]int),
visiting: make(map[Type]bool),
fields: make([]StructField, 0, .NumField()),
index: make([]int, 0, 2),
}
.walk()
// Remove all the fields that have been hidden.
// Use an in-place removal that avoids copying in
// the common case that there are no hidden fields.
:= 0
for := range .fields {
:= &.fields[]
if .Name == "" {
continue
}
if != {
// A field has been removed. We need to shuffle
// all the subsequent elements up.
.fields[] = *
}
++
}
return .fields[:]
}
type visibleFieldsWalker struct {
byName map[string]int
visiting map[Type]bool
fields []StructField
index []int
}
// walk walks all the fields in the struct type t, visiting
// fields in index preorder and appending them to w.fields
// (this maintains the required ordering).
// Fields that have been overridden have their
// Name field cleared.
func ( *visibleFieldsWalker) ( Type) {
if .visiting[] {
return
}
.visiting[] = true
for := 0; < .NumField(); ++ {
:= .Field()
.index = append(.index, )
:= true
if , := .byName[.Name]; {
:= &.fields[]
if len(.index) == len(.Index) {
// Fields with the same name at the same depth
// cancel one another out. Set the field name
// to empty to signify that has happened, and
// there's no need to add this field.
.Name = ""
= false
} else if len(.index) < len(.Index) {
// The old field loses because it's deeper than the new one.
.Name = ""
} else {
// The old field wins because it's shallower than the new one.
= false
}
}
if {
// Copy the index so that it's not overwritten
// by the other appends.
.Index = append([]int(nil), .index...)
.byName[.Name] = len(.fields)
.fields = append(.fields, )
}
if .Anonymous {
if .Type.Kind() == Pointer {
.Type = .Type.Elem()
}
if .Type.Kind() == Struct {
.(.Type)
}
}
.index = .index[:len(.index)-1]
}
delete(.visiting, )
}
The pages are generated with Golds v0.4.9. (GOOS=linux GOARCH=amd64)