github.com/searKing/golang/go@v1.2.117/reflect/walk.go (about)

     1  // Copyright 2020 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package reflect
     6  
     7  import (
     8  	"reflect"
     9  )
    10  
    11  // Walk walks down v
    12  func Walk(t reflect.Type, visitedOnce bool, do func(s reflect.Type, sf reflect.StructField) (stop bool)) {
    13  	// Anonymous fields to explore at the current level and the next.
    14  	var current []reflect.Type
    15  	next := []reflect.Type{t}
    16  
    17  	// Count of queued names for current level and the next.
    18  	currentCount := map[reflect.Type]int{}
    19  	nextCount := map[reflect.Type]int{}
    20  
    21  	// Types already visited at an earlier level.
    22  	// FIXME I havenot seen any case which can trigger visited
    23  	visited := map[reflect.Type]bool{}
    24  	for len(next) > 0 {
    25  		current, next = next, current[:0]
    26  		currentCount, nextCount = nextCount, map[reflect.Type]int{}
    27  
    28  		for _, typ := range current {
    29  
    30  			if typ.Kind() == reflect.Ptr {
    31  				// Follow pointer.
    32  				typ = typ.Elem()
    33  			}
    34  			if visitedOnce {
    35  				if visited[typ] {
    36  					continue
    37  				}
    38  				visited[typ] = true
    39  			}
    40  
    41  			if typ.Kind() != reflect.Struct {
    42  				if do(typ, reflect.StructField{}) {
    43  					return
    44  				}
    45  				continue
    46  			}
    47  			// Scan typ for fields to include.
    48  			for i := 0; i < typ.NumField(); i++ {
    49  				sf := typ.Field(i)
    50  				if do(typ, sf) {
    51  					continue
    52  				}
    53  
    54  				ft := sf.Type
    55  				if ft.Name() == "" && ft.Kind() == reflect.Ptr {
    56  					// Follow pointer.
    57  					ft = ft.Elem()
    58  				}
    59  
    60  				// Record found field and index sequence.
    61  				if ft.Name() != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
    62  					if currentCount[typ] > 1 {
    63  					}
    64  					//continue
    65  				}
    66  				// Record new anonymous struct to explore in next round.
    67  				nextCount[ft]++
    68  				if !visitedOnce || nextCount[ft] == 1 {
    69  					next = append(next, ft)
    70  				}
    71  			}
    72  		}
    73  	}
    74  
    75  }