github.com/gogf/gf@v1.16.9/internal/structs/structs_type.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/gogf/gf.
     6  
     7  package structs
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"reflect"
    13  )
    14  
    15  // StructType retrieves and returns the struct Type of specified struct/*struct.
    16  // The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.
    17  func StructType(object interface{}) (*Type, error) {
    18  	var (
    19  		reflectValue reflect.Value
    20  		reflectKind  reflect.Kind
    21  		reflectType  reflect.Type
    22  	)
    23  	if rv, ok := object.(reflect.Value); ok {
    24  		reflectValue = rv
    25  	} else {
    26  		reflectValue = reflect.ValueOf(object)
    27  	}
    28  	reflectKind = reflectValue.Kind()
    29  	for {
    30  		switch reflectKind {
    31  		case reflect.Ptr:
    32  			if !reflectValue.IsValid() || reflectValue.IsNil() {
    33  				// If pointer is type of *struct and nil, then automatically create a temporary struct.
    34  				reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
    35  				reflectKind = reflectValue.Kind()
    36  			} else {
    37  				reflectValue = reflectValue.Elem()
    38  				reflectKind = reflectValue.Kind()
    39  			}
    40  
    41  		case reflect.Array, reflect.Slice:
    42  			reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
    43  			reflectKind = reflectValue.Kind()
    44  
    45  		default:
    46  			goto exitLoop
    47  		}
    48  	}
    49  
    50  exitLoop:
    51  	for reflectKind == reflect.Ptr {
    52  		reflectValue = reflectValue.Elem()
    53  		reflectKind = reflectValue.Kind()
    54  	}
    55  	if reflectKind != reflect.Struct {
    56  		return nil, errors.New(
    57  			fmt.Sprintf(
    58  				`invalid object kind "%s", kind of "struct" is required`,
    59  				reflectKind,
    60  			),
    61  		)
    62  	}
    63  	reflectType = reflectValue.Type()
    64  	return &Type{
    65  		Type: reflectType,
    66  	}, nil
    67  }
    68  
    69  // Signature returns a unique string as this type.
    70  func (t Type) Signature() string {
    71  	return t.PkgPath() + "/" + t.String()
    72  }
    73  
    74  // FieldKeys returns the keys of current struct/map.
    75  func (t Type) FieldKeys() []string {
    76  	keys := make([]string, t.NumField())
    77  	for i := 0; i < t.NumField(); i++ {
    78  		keys[i] = t.Field(i).Name
    79  	}
    80  	return keys
    81  }