代码拉取完成,页面将自动刷新
package field
import (
"reflect"
)
// Field is a controller's field
// contains all the necessary, internal, information
// to work with.
type Field struct {
Name string // the field's original name
// but if a tag with `name: "other"`
// exist then this fill is filled, otherwise it's the same as the Name.
TagName string
Index int
Type reflect.Type
Value reflect.Value
embedded *Field
}
// GetIndex returns all the "dimensions"
// of the controller struct field's position that this field is referring to,
// recursively.
// Usage: elem.FieldByIndex(field.getIndex())
// for example the {0,1} means that the field is on the second field of the first's
// field of this struct.
func (ff Field) GetIndex() []int {
deepIndex := []int{ff.Index}
if emb := ff.embedded; emb != nil {
deepIndex = append(deepIndex, emb.GetIndex()...)
}
return deepIndex
}
// GetType returns the type of the referring field, recursively.
func (ff Field) GetType() reflect.Type {
typ := ff.Type
if emb := ff.embedded; emb != nil {
return emb.GetType()
}
return typ
}
// GetFullName returns the full name of that field
// i.e: UserController.SessionController.Manager,
// it's useful for debugging only.
func (ff Field) GetFullName() string {
name := ff.Name
if emb := ff.embedded; emb != nil {
return name + "." + emb.GetFullName()
}
return name
}
// GetTagName returns the tag name of the referring field
// recursively.
func (ff Field) GetTagName() string {
name := ff.TagName
if emb := ff.embedded; emb != nil {
return emb.GetTagName()
}
return name
}
// checkVal checks if that value
// is valid to be set-ed to the new controller's instance.
// Used on binder.
func checkVal(val reflect.Value) bool {
return val.IsValid() && (val.Kind() == reflect.Ptr && !val.IsNil()) && val.CanInterface()
}
// GetValue returns a valid value of the referring field, recursively.
func (ff Field) GetValue() interface{} {
if ff.embedded != nil {
return ff.embedded.GetValue()
}
if checkVal(ff.Value) {
return ff.Value.Interface()
}
return "undefinied value"
}
// SendTo should be used when this field or its embedded
// has a Value on it.
// It sets the field's value to the "elem" instance, it's the new controller.
func (ff Field) SendTo(elem reflect.Value) {
// note:
// we don't use the getters here
// because we do recursively search by our own here
// to be easier to debug if ever needed.
if embedded := ff.embedded; embedded != nil {
if ff.Index >= 0 {
embedded.SendTo(elem.Field(ff.Index))
}
return
}
elemField := elem.Field(ff.Index)
if elemField.Kind() == reflect.Ptr && !elemField.IsNil() {
return
}
elemField.Set(ff.Value)
}
// lookupTagName checks if the "elemField" struct's field
// contains a tag `name`, if it contains then it returns its value
// otherwise returns the field's original Name.
func lookupTagName(elemField reflect.StructField) string {
vname := elemField.Name
if taggedName, ok := elemField.Tag.Lookup("name"); ok {
vname = taggedName
}
return vname
}
// LookupFields iterates all "elem"'s fields and its fields
// if structs, recursively.
// Compares them to the "matcher", if they passed
// then it executes the "handler" if any,
// the handler can change the field as it wants to.
//
// It finally returns that collection of the valid fields, can be empty.
func LookupFields(elem reflect.Type, matcher func(reflect.StructField) bool, handler func(*Field)) (fields []Field) {
for i, n := 0, elem.NumField(); i < n; i++ {
elemField := elem.Field(i)
if matcher(elemField) {
field := Field{
Index: i,
Name: elemField.Name,
TagName: lookupTagName(elemField),
Type: elemField.Type,
}
if handler != nil {
handler(&field)
}
// we area inside the correct type
fields = append(fields, field)
continue
}
f := lookupStructField(elemField.Type, matcher, handler)
if f != nil {
fields = append(fields, Field{
Index: i,
Name: elemField.Name,
Type: elemField.Type,
embedded: f,
})
}
}
return
}
// lookupStructField is here to search for embedded field only,
// is working with the "lookupFields".
// We could just one one function
// for both structured (embedded) fields and normal fields
// but we keep that as it's, a new function like this
// is easier for debugging, if ever needed.
func lookupStructField(elem reflect.Type, matcher func(reflect.StructField) bool, handler func(*Field)) *Field {
// fmt.Printf("lookup struct for elem: %s\n", elem.Name())
// ignore if that field is not a struct
if elem.Kind() != reflect.Struct {
return nil
}
// search by fields.
for i, n := 0, elem.NumField(); i < n; i++ {
elemField := elem.Field(i)
if matcher(elemField) {
// we area inside the correct type.
f := &Field{
Index: i,
Name: elemField.Name,
TagName: lookupTagName(elemField),
Type: elemField.Type,
}
if handler != nil {
handler(f)
}
return f
}
// if field is struct and the value is struct
// then try inside its fields for a compatible
// field type.
if elemField.Type.Kind() == reflect.Struct { // 3-level
elemFieldEmb := elem.Field(i)
f := lookupStructField(elemFieldEmb.Type, matcher, handler)
if f != nil {
fp := &Field{
Index: i,
Name: elemFieldEmb.Name,
TagName: lookupTagName(elemFieldEmb),
Type: elemFieldEmb.Type,
embedded: f,
}
return fp
}
}
}
return nil
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。