Как получить тег поля без использования имени поля в качестве строки? - PullRequest
1 голос
/ 19 июня 2019

Можно ли получить тег поля, используя функцию, которая получает только структуру и само поле?

Я знаю, что могу сделать что-то вроде этого:

reflect.TypeOf(x).FieldByName("FieldNameAsString").Tag

Но я не хочу использовать имя поля в качестве строки в этом случае, потому что оно может быть переименовано в будущем, так что лучше вместо этого использовать само поле.

type MyStruct struct {
    MyField string `thetag:"hello"`
}

func main() {
    x := MyStruct{}
    getTag(x, x.MyField)
}

1 Ответ

4 голосов
/ 19 июня 2019

Используйте смещения, чтобы найти поле:

// getTag returns the tag for a field given a pointer to
// a struct and a pointer to the field in that struct.
func getTag(pv interface{}, pf interface{}) reflect.StructTag {
    v := reflect.ValueOf(pv)
    offset := reflect.ValueOf(pf).Pointer() - v.Pointer()

    t := v.Type().Elem()
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        if f.Offset == offset {
            return f.Tag
        }
    }
    return ""
}

Запустите его на детской площадке .

В приведенном выше коде предполагается, что сборщик мусора не перемещает структуру между вызовами to в Pointer . Это предположение верно сегодня, но может не соответствовать действительности в будущем. Используйте пакет unsafe , чтобы защитить код от будущих изменений в сборщике мусора:

// getTag returns the tag for a field with the given offset
// in the struct pointed to by pv.
func getTag(pv interface{}, offset uintptr) reflect.StructTag {
    t := reflect.TypeOf(pv).Elem()
    for i := 0; i < t.NumField(); i++ {
        f := t.Field(i)
        if f.Offset == offset {
            return f.Tag
        }
    }
    return ""
}

Назовите это так:

x := MyStruct{}
fmt.Println(getTag(&x, unsafe.Offsetof(x.MyField)))

Запустите его на игровой площадке .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...