github.com/kaydxh/golang@v0.0.131/go/reflect/struct.go (about)

     1  /*
     2   *Copyright (c) 2022, kaydxh
     3   *
     4   *Permission is hereby granted, free of charge, to any person obtaining a copy
     5   *of this software and associated documentation files (the "Software"), to deal
     6   *in the Software without restriction, including without limitation the rights
     7   *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   *copies of the Software, and to permit persons to whom the Software is
     9   *furnished to do so, subject to the following conditions:
    10   *
    11   *The above copyright notice and this permission notice shall be included in all
    12   *copies or substantial portions of the Software.
    13   *
    14   *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   *SOFTWARE.
    21   */
    22  package reflect
    23  
    24  import (
    25  	"reflect"
    26  )
    27  
    28  //req must be pointer to struct
    29  // IsNil reports whether its argument v is nil. The argument must be
    30  // a chan, func, interface, map, pointer, or slice value; if it is
    31  // not, IsNil panics. Note that IsNil is not always equivalent to a
    32  // regular comparison with nil in Go. For example, if v was created
    33  // by calling ValueOf with an uninitialized interface variable i,
    34  // i==nil will be true but v.IsNil will panic as v will be the zero
    35  // Value.
    36  func indirectStruct(req interface{}) (reflect.Value, bool) {
    37  	if req == nil {
    38  		return reflect.Value{}, false
    39  	}
    40  
    41  	v := reflect.ValueOf(req)
    42  	/*
    43  		if v.IsNil() {
    44  			return reflect.Value{}, false
    45  		}
    46  	*/
    47  
    48  	return reflect.Indirect(v), true
    49  }
    50  
    51  func RetrieveStructField(req interface{}, name string) string {
    52  	v, ok := indirectStruct(req)
    53  	if !ok {
    54  		return ""
    55  	}
    56  
    57  	if !v.IsValid() {
    58  		return ""
    59  	}
    60  
    61  	//nested field: reflect.Indirect(v).FieldByName("layout1").Index(0).FieldByName("layout2")
    62  	f := v.FieldByName(name)
    63  	if f.IsValid() && f.Kind() == reflect.String {
    64  		return f.String()
    65  	}
    66  	return ""
    67  
    68  }
    69  
    70  func TrySetStructFiled(req interface{}, name, value string) {
    71  	v, ok := indirectStruct(req)
    72  	if !ok {
    73  		return
    74  	}
    75  
    76  	if !v.IsValid() {
    77  		return
    78  	}
    79  
    80  	f := v.FieldByName(name)
    81  	if f.IsValid() && f.Kind() == reflect.String {
    82  		f.SetString(value)
    83  	}
    84  }
    85  
    86  func AllFieldTags(req interface{}, key string) []string {
    87  	return fieldTags(req, key, false)
    88  }
    89  
    90  // req must be struct(Not pointer to struct), or return nil(tt.Field() will panic)
    91  // key for tag , db or json, if key is empty, use field name instead
    92  func NonzeroFieldTags(req interface{}, key string) []string {
    93  	return fieldTags(req, key, true)
    94  }
    95  
    96  // req must be struct(Not pointer to struct), or return nil(tt.Field() will panic)
    97  // key for tag , db or json, if key is empty, use field name instead
    98  //nonzere true, noly return field tags for values that nonzero
    99  func fieldTags(req interface{}, key string, nonzero bool) []string {
   100  	var tags []string
   101  
   102  	tagsValues := fieldTagsValues(req, key, nonzero)
   103  	for tag := range tagsValues {
   104  		tags = append(tags, tag)
   105  	}
   106  
   107  	return tags
   108  }
   109  
   110  // only get export Fields
   111  func AllTagsValues(req interface{}, key string) map[string]interface{} {
   112  	return fieldTagsValues(req, key, false)
   113  }
   114  
   115  // req must be struct(Not pointer to struct), or return nil(tt.Field() will panic)
   116  // key for tag , db or json ..., if key is empty or tag is empty, ignore it
   117  // nonzere true, noly return field tags for values that nonzero
   118  func fieldTagsValues(req interface{}, key string, nonzero bool) map[string]interface{} {
   119  	if req == nil {
   120  		return nil
   121  	}
   122  
   123  	v, ok := indirectStruct(req)
   124  	if !ok {
   125  		return nil
   126  	}
   127  	if !v.IsValid() {
   128  		return nil
   129  	}
   130  
   131  	tt := reflect.TypeOf(req)
   132  	if tt.Kind() == reflect.Ptr {
   133  		tt = tt.Elem()
   134  	}
   135  
   136  	if tt.Kind() != reflect.Struct {
   137  		return nil
   138  	}
   139  
   140  	tagsValues := make(map[string]interface{})
   141  	for i := 0; i < tt.NumField(); i++ {
   142  		field := tt.Field(i)
   143  		property := string(field.Name)
   144  		f := v.FieldByName(property)
   145  
   146  		if !f.CanInterface() {
   147  			continue
   148  		}
   149  
   150  		if nonzero {
   151  			if IsZeroValue(f) {
   152  				continue
   153  			}
   154  		}
   155  
   156  		if key == "" {
   157  			continue
   158  		}
   159  
   160  		tag := field.Tag.Get(key)
   161  		if len(tag) > 0 {
   162  			// field.Type.Name() -> "string", "int64" ...
   163  			tagsValues[tag] = f.Interface()
   164  		}
   165  	}
   166  
   167  	return tagsValues
   168  }