github.com/zhongdalu/gf@v1.0.0/g/internal/structs/structs_tag.go (about)

     1  // Copyright 2019 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/zhongdalu/gf.
     6  
     7  package structs
     8  
     9  import (
    10  	"reflect"
    11  
    12  	"github.com/zhongdalu/gf/third/github.com/fatih/structs"
    13  )
    14  
    15  // TagMapName retrieves struct tags as map[tag]attribute from <pointer>, and returns it.
    16  //
    17  // The parameter <recursive> specifies whether retrieving the struct field recursively.
    18  //
    19  // Note that it only retrieves the exported attributes with first letter up-case from struct.
    20  func TagMapName(pointer interface{}, priority []string, recursive bool) map[string]string {
    21  	tagMap := TagMapField(pointer, priority, recursive)
    22  	if len(tagMap) > 0 {
    23  		m := make(map[string]string, len(tagMap))
    24  		for k, v := range tagMap {
    25  			m[k] = v.Name()
    26  		}
    27  		return m
    28  	}
    29  	return nil
    30  }
    31  
    32  // TagMapField retrieves struct tags as map[tag]*Field from <pointer>, and returns it.
    33  //
    34  // The parameter <recursive> specifies whether retrieving the struct field recursively.
    35  //
    36  // Note that it only retrieves the exported attributes with first letter up-case from struct.
    37  func TagMapField(pointer interface{}, priority []string, recursive bool) map[string]*Field {
    38  	tagMap := make(map[string]*Field)
    39  	fields := ([]*structs.Field)(nil)
    40  	if v, ok := pointer.(reflect.Value); ok {
    41  		fields = structs.Fields(v.Interface())
    42  	} else {
    43  		rv := reflect.ValueOf(pointer)
    44  		kind := rv.Kind()
    45  		if kind == reflect.Ptr {
    46  			rv = rv.Elem()
    47  			kind = rv.Kind()
    48  		}
    49  		// If pointer is type of **struct and nil, then automatically create a temporary struct,
    50  		// which is used for structs.Fields.
    51  		if kind == reflect.Ptr && (!rv.IsValid() || rv.IsNil()) {
    52  			fields = structs.Fields(reflect.New(rv.Type().Elem()).Elem().Interface())
    53  		} else {
    54  			fields = structs.Fields(pointer)
    55  		}
    56  	}
    57  	tag := ""
    58  	name := ""
    59  	for _, field := range fields {
    60  		name = field.Name()
    61  		// Only retrieve exported attributes.
    62  		if name[0] < byte('A') || name[0] > byte('Z') {
    63  			continue
    64  		}
    65  
    66  		tag = ""
    67  		for _, p := range priority {
    68  			tag = field.Tag(p)
    69  			if tag != "" {
    70  				break
    71  			}
    72  		}
    73  		if tag != "" {
    74  			tagMap[tag] = field
    75  		}
    76  		if recursive {
    77  			rv := reflect.ValueOf(field.Value())
    78  			kind := rv.Kind()
    79  			if kind == reflect.Ptr {
    80  				rv = rv.Elem()
    81  				kind = rv.Kind()
    82  			}
    83  			if kind == reflect.Struct {
    84  				for k, v := range TagMapField(rv, priority, true) {
    85  					if _, ok := tagMap[k]; !ok {
    86  						tagMap[k] = v
    87  					}
    88  				}
    89  			}
    90  		}
    91  	}
    92  	return tagMap
    93  }