mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
This pull request standardizes the use of the Go 1.18+ `any` type alias
instead of `interface{}` throughout the codebase. The change improves
code readability and aligns with modern Go best practices. The update
touches many files, including core data structures, code generation
templates, logging utilities, and test data, ensuring consistency across
all usages.
**Type alias migration to `any`:**
* Replaced all instances of `interface{}` with `any` in core data
structures such as `garray` and in generated model structs (e.g.,
`TableUser`, `User1`, `User2`) to modernize type usage.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
* Updated function signatures, method parameters, and return types from
`interface{}` to `any` in various parts of the codebase, including code
generation, service logic, and logging utilities (e.g., `mlog`).
[[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74)
[[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
[[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107)
[[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121)
[[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112)
[[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36)
[[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74)
[[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96)
**Generated code and templates:**
* Adjusted generated files and code generation templates to output `any`
instead of `interface{}` for relevant struct fields and function
signatures, ensuring that new code generation aligns with the updated
convention.
[[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
[[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
**Container and utility updates:**
* Refactored the `garray` container implementation and related
constructors/methods to use `[]any` instead of `[]interface{}`, along
with corresponding function signatures.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52)
[[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62)
[[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86)
[[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97)
[[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114)
[[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124)
[[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143)
[[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167)
These changes collectively modernize the codebase and prepare it for
future Go developments by using the idiomatic `any` type.
267 lines
7.5 KiB
Go
267 lines
7.5 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
// Package gstructs provides functions for struct information retrieving.
|
|
package gstructs
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
)
|
|
|
|
// Type wraps reflect.Type for additional features.
|
|
type Type struct {
|
|
reflect.Type
|
|
}
|
|
|
|
// Field contains information of a struct field .
|
|
type Field struct {
|
|
Value reflect.Value // The underlying value of the field.
|
|
Field reflect.StructField // The underlying field of the field.
|
|
|
|
// Retrieved tag name. It depends TagValue.
|
|
TagName string
|
|
|
|
// Retrieved tag value.
|
|
// There might be more than one tags in the field,
|
|
// but only one can be retrieved according to calling function rules.
|
|
TagValue string
|
|
}
|
|
|
|
// FieldsInput is the input parameter struct type for function Fields.
|
|
type FieldsInput struct {
|
|
// Pointer should be type of struct/*struct.
|
|
// TODO this attribute name is not suitable, which would make confuse.
|
|
Pointer any
|
|
|
|
// RecursiveOption specifies the way retrieving the fields recursively if the attribute
|
|
// is an embedded struct. It is RecursiveOptionNone in default.
|
|
RecursiveOption RecursiveOption
|
|
}
|
|
|
|
// FieldMapInput is the input parameter struct type for function FieldMap.
|
|
type FieldMapInput struct {
|
|
// Pointer should be type of struct/*struct.
|
|
// TODO this attribute name is not suitable, which would make confuse.
|
|
Pointer any
|
|
|
|
// PriorityTagArray specifies the priority tag array for retrieving from high to low.
|
|
// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
|
|
PriorityTagArray []string
|
|
|
|
// RecursiveOption specifies the way retrieving the fields recursively if the attribute
|
|
// is an embedded struct. It is RecursiveOptionNone in default.
|
|
RecursiveOption RecursiveOption
|
|
}
|
|
|
|
type RecursiveOption int
|
|
|
|
const (
|
|
RecursiveOptionNone RecursiveOption = iota // No recursively retrieving fields as map if the field is an embedded struct.
|
|
RecursiveOptionEmbedded // Recursively retrieving fields as map if the field is an embedded struct.
|
|
RecursiveOptionEmbeddedNoTag // Recursively retrieving fields as map if the field is an embedded struct and the field has no tag.
|
|
)
|
|
|
|
// Fields retrieves and returns the fields of `pointer` as slice.
|
|
func Fields(in FieldsInput) ([]Field, error) {
|
|
var (
|
|
ok bool
|
|
fieldFilterMap = make(map[string]struct{})
|
|
retrievedFields = make([]Field, 0)
|
|
currentLevelFieldMap = make(map[string]Field)
|
|
rangeFields, err = getFieldValues(in.Pointer)
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for index := 0; index < len(rangeFields); index++ {
|
|
field := rangeFields[index]
|
|
currentLevelFieldMap[field.Name()] = field
|
|
}
|
|
|
|
for index := 0; index < len(rangeFields); index++ {
|
|
field := rangeFields[index]
|
|
if _, ok = fieldFilterMap[field.Name()]; ok {
|
|
continue
|
|
}
|
|
if field.IsEmbedded() {
|
|
if in.RecursiveOption != RecursiveOptionNone {
|
|
switch in.RecursiveOption {
|
|
case RecursiveOptionEmbeddedNoTag:
|
|
if field.TagStr() != "" {
|
|
break
|
|
}
|
|
fallthrough
|
|
|
|
case RecursiveOptionEmbedded:
|
|
structFields, err := Fields(FieldsInput{
|
|
Pointer: field.Value,
|
|
RecursiveOption: in.RecursiveOption,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// The current level fields can overwrite the sub-struct fields with the same name.
|
|
for i := 0; i < len(structFields); i++ {
|
|
var (
|
|
structField = structFields[i]
|
|
fieldName = structField.Name()
|
|
)
|
|
if _, ok = fieldFilterMap[fieldName]; ok {
|
|
continue
|
|
}
|
|
fieldFilterMap[fieldName] = struct{}{}
|
|
if v, ok := currentLevelFieldMap[fieldName]; !ok {
|
|
retrievedFields = append(retrievedFields, structField)
|
|
} else {
|
|
retrievedFields = append(retrievedFields, v)
|
|
}
|
|
}
|
|
continue
|
|
default:
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
fieldFilterMap[field.Name()] = struct{}{}
|
|
retrievedFields = append(retrievedFields, field)
|
|
}
|
|
return retrievedFields, nil
|
|
}
|
|
|
|
// FieldMap retrieves and returns struct field as map[name/tag]Field from `pointer`.
|
|
//
|
|
// The parameter `pointer` should be type of struct/*struct.
|
|
//
|
|
// The parameter `priority` specifies the priority tag array for retrieving from high to low.
|
|
// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
|
|
//
|
|
// The parameter `recursive` specifies whether retrieving the fields recursively if the attribute
|
|
// is an embedded struct.
|
|
//
|
|
// Note that it only retrieves the exported attributes with first letter upper-case from struct.
|
|
func FieldMap(in FieldMapInput) (map[string]Field, error) {
|
|
fields, err := getFieldValues(in.Pointer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var (
|
|
tagValue string
|
|
mapField = make(map[string]Field)
|
|
)
|
|
for _, field := range fields {
|
|
// Only retrieve exported attributes.
|
|
if !field.IsExported() {
|
|
continue
|
|
}
|
|
tagValue = ""
|
|
for _, p := range in.PriorityTagArray {
|
|
tagValue = field.Tag(p)
|
|
if tagValue != "" && tagValue != "-" {
|
|
break
|
|
}
|
|
}
|
|
tempField := field
|
|
tempField.TagValue = tagValue
|
|
if tagValue != "" {
|
|
mapField[tagValue] = tempField
|
|
} else {
|
|
if in.RecursiveOption != RecursiveOptionNone && field.IsEmbedded() {
|
|
switch in.RecursiveOption {
|
|
case RecursiveOptionEmbeddedNoTag:
|
|
if field.TagStr() != "" {
|
|
mapField[field.Name()] = tempField
|
|
break
|
|
}
|
|
fallthrough
|
|
|
|
case RecursiveOptionEmbedded:
|
|
m, err := FieldMap(FieldMapInput{
|
|
Pointer: field.Value,
|
|
PriorityTagArray: in.PriorityTagArray,
|
|
RecursiveOption: in.RecursiveOption,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for k, v := range m {
|
|
if _, ok := mapField[k]; !ok {
|
|
tempV := v
|
|
mapField[k] = tempV
|
|
}
|
|
}
|
|
default:
|
|
}
|
|
} else {
|
|
mapField[field.Name()] = tempField
|
|
}
|
|
}
|
|
}
|
|
return mapField, nil
|
|
}
|
|
|
|
// StructType retrieves and returns the struct Type of specified struct/*struct.
|
|
// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.
|
|
func StructType(object any) (*Type, error) {
|
|
// if already reflect.Type
|
|
if reflectType, ok := object.(reflect.Type); ok {
|
|
for reflectType.Kind() == reflect.Pointer {
|
|
reflectType = reflectType.Elem()
|
|
}
|
|
if reflectType.Kind() == reflect.Struct {
|
|
return &Type{
|
|
Type: reflectType,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
var (
|
|
reflectValue reflect.Value
|
|
reflectKind reflect.Kind
|
|
reflectType reflect.Type
|
|
)
|
|
if rv, ok := object.(reflect.Value); ok {
|
|
reflectValue = rv
|
|
} else {
|
|
reflectValue = reflect.ValueOf(object)
|
|
}
|
|
reflectKind = reflectValue.Kind()
|
|
for {
|
|
switch reflectKind {
|
|
case reflect.Pointer:
|
|
if !reflectValue.IsValid() || reflectValue.IsNil() {
|
|
// If pointer is type of *struct and nil, then automatically create a temporary struct.
|
|
reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
|
|
reflectKind = reflectValue.Kind()
|
|
} else {
|
|
reflectValue = reflectValue.Elem()
|
|
reflectKind = reflectValue.Kind()
|
|
}
|
|
|
|
case reflect.Array, reflect.Slice:
|
|
reflectValue = reflect.New(reflectValue.Type().Elem()).Elem()
|
|
reflectKind = reflectValue.Kind()
|
|
|
|
default:
|
|
goto exitLoop
|
|
}
|
|
}
|
|
|
|
exitLoop:
|
|
if reflectKind != reflect.Struct {
|
|
return nil, gerror.Newf(
|
|
`invalid object kind "%s", kind of "struct" is required`,
|
|
reflectKind,
|
|
)
|
|
}
|
|
reflectType = reflectValue.Type()
|
|
return &Type{
|
|
Type: reflectType,
|
|
}, nil
|
|
}
|