github.com/wangyougui/gf/v2@v2.6.5/util/gutil/gutil_struct.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). 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/wangyougui/gf.
     6  
     7  package gutil
     8  
     9  import (
    10  	"reflect"
    11  
    12  	"github.com/wangyougui/gf/v2/errors/gcode"
    13  	"github.com/wangyougui/gf/v2/errors/gerror"
    14  	"github.com/wangyougui/gf/v2/os/gstructs"
    15  	"github.com/wangyougui/gf/v2/util/gconv"
    16  )
    17  
    18  // StructToSlice converts struct to slice of which all keys and values are its items.
    19  // Eg: {"K1": "v1", "K2": "v2"} => ["K1", "v1", "K2", "v2"]
    20  func StructToSlice(data interface{}) []interface{} {
    21  	var (
    22  		reflectValue = reflect.ValueOf(data)
    23  		reflectKind  = reflectValue.Kind()
    24  	)
    25  	for reflectKind == reflect.Ptr {
    26  		reflectValue = reflectValue.Elem()
    27  		reflectKind = reflectValue.Kind()
    28  	}
    29  	switch reflectKind {
    30  	case reflect.Struct:
    31  		array := make([]interface{}, 0)
    32  		// Note that, it uses the gconv tag name instead of the attribute name if
    33  		// the gconv tag is fined in the struct attributes.
    34  		for k, v := range gconv.Map(reflectValue) {
    35  			array = append(array, k)
    36  			array = append(array, v)
    37  		}
    38  		return array
    39  	}
    40  	return nil
    41  }
    42  
    43  // FillStructWithDefault fills  attributes of pointed struct with tag value from `default/d` tag .
    44  // The parameter `structPtr` should be either type of *struct/[]*struct.
    45  func FillStructWithDefault(structPtr interface{}) error {
    46  	var (
    47  		reflectValue reflect.Value
    48  	)
    49  	if rv, ok := structPtr.(reflect.Value); ok {
    50  		reflectValue = rv
    51  	} else {
    52  		reflectValue = reflect.ValueOf(structPtr)
    53  	}
    54  	switch reflectValue.Kind() {
    55  	case reflect.Ptr:
    56  		// Nothing to do.
    57  	case reflect.Array, reflect.Slice:
    58  		if reflectValue.Elem().Kind() != reflect.Ptr {
    59  			return gerror.NewCodef(
    60  				gcode.CodeInvalidParameter,
    61  				`invalid parameter "%s", the element of slice should be type of pointer of struct, but given "%s"`,
    62  				reflectValue.Type().String(), reflectValue.Elem().Type().String(),
    63  			)
    64  		}
    65  	default:
    66  		return gerror.NewCodef(
    67  			gcode.CodeInvalidParameter,
    68  			`invalid parameter "%s", should be type of pointer of struct`,
    69  			reflectValue.Type().String(),
    70  		)
    71  	}
    72  	if reflectValue.IsNil() {
    73  		return gerror.NewCode(
    74  			gcode.CodeInvalidParameter,
    75  			`the pointed struct object should not be nil`,
    76  		)
    77  	}
    78  	if !reflectValue.Elem().IsValid() {
    79  		return gerror.NewCode(
    80  			gcode.CodeInvalidParameter,
    81  			`the pointed struct object should be valid`,
    82  		)
    83  	}
    84  	fields, err := gstructs.Fields(gstructs.FieldsInput{
    85  		Pointer:         reflectValue,
    86  		RecursiveOption: gstructs.RecursiveOptionEmbedded,
    87  	})
    88  	if err != nil {
    89  		return err
    90  	}
    91  	for _, field := range fields {
    92  		if field.OriginalKind() == reflect.Struct {
    93  			err := FillStructWithDefault(field.OriginalValue().Addr())
    94  			if err != nil {
    95  				return err
    96  			}
    97  			continue
    98  		}
    99  
   100  		if defaultValue := field.TagDefault(); defaultValue != "" {
   101  			if field.IsEmpty() {
   102  				field.Value.Set(reflect.ValueOf(
   103  					gconv.ConvertWithRefer(defaultValue, field.Value),
   104  				))
   105  			}
   106  		}
   107  	}
   108  
   109  	return nil
   110  }