Подтвердить что ты не робот

Как получить базовую ценность от рефлексии. Знать в голанге?

Итак, я нашел код, который помогает мне начать работу с отражением в Go (golang), но мне трудно получить базовое значение, чтобы я мог в принципе создать map[string]string из структуры и полей.

В конце концов, я хотел бы сделать результат в map[string]interface{}, но эта проблема как бы блокирует меня.

Код, который у меня есть на данный момент:

package main

import (
    "fmt"
    "reflect"
)

type Foo struct {
    FirstName string `tag_name:"tag 1"`
    LastName  string `tag_name:"tag 2"`
    Age       int  `tag_name:"tag 3"`
}

func inspect(f interface{}) map[string]string {

    m := make(map[string]string)
    val := reflect.ValueOf(f).Elem()

    for i := 0; i < val.NumField(); i++ {
        valueField := val.Field(i)
        typeField := val.Type().Field(i)

        f := valueField.Interface()
        val := reflect.ValueOf(f)
        m[typeField.Name] = val.String()
    }

    return m
}

func dump(m map[string]string) {

    for k, v := range m {
        fmt.Printf("%s : %s\n", k, v)
    }
}

func main() {
    f := &Foo{
        FirstName: "Drew",
        LastName:  "Olson",
        Age:       30,
    }

    a := inspect(f)

    dump(a)
}

Результат выполнения кода:

FirstName : Drew
LastName : Olson
Age : <int Value>

Из того, что я понимаю, вывод для FirstName и LastName является фактическим отражением. Объекты, но для строк метод String() по значению просто выводит базовую строку. Я хотел бы либо получить int, либо изменить его в строку, но из документации о дефектном пакете я не сразу вижу, как это делается.

Су... Как получить базовое значение от отражения. Значение в golang?

4b9b3361

Ответ 1

Хорошим примером того, как анализировать значения, является пакет fmt. См. этот код.

Использование указанного кода для соответствия вашей проблеме будет выглядеть следующим образом:

switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    m[typeField.Name] = strconv.FormatInt(val.Int(), 10)
case reflect.String:
    m[typeField.Name] = val.String()    
// etc...
}

В основном вам нужно проверить все доступные виды.

Ответ 2

Похоже, ты на правильном пути. Проблема, которую я вижу с вашим кодом, заключается в предположениях о значениях, что означает, когда вы вызываете Elem() и сколько раз (для решения указателей). Чтобы узнать это, вам нужно посмотреть reflect.Kind. Является ли значение a reflect.Ptr? Затем используйте Elem().

После того, как вы получили значение от val.Interface()/val.String()/val.Int(), вы можете конвертировать ваши значения по мере необходимости. То, что вы используете, будет зависеть от reflect.Kind. Чтобы преобразовать int в/из string, вам нужно использовать пакет strconv.

Пакеты encoding/json и encoding/xml уже выполняют эту работу. Исходный код содержит несколько отличных примеров. Например, посмотрите copyValue в encoding/xml/read.go и marshalSimple в encoding/xml/marshal.go.

Ответ 3

Это должно быть проще сделать с Go 1.5 (август 2015 г.) См. отзыв 8731 и зафиксировать 049b89d Rob Pike (robpike):

fmt: обрабатывать reflect.Value специально - как значение, которое оно имеет

Это позволит вам распечатать фактическое значение аргумента Reflect.Value():

Когда a reflect.Value передается на Printf (и т.д.), fmt называется методом String, который не раскрывает его содержимое.
Чтобы получить содержимое, можно вызвать Value.Interface(), но это незаконно если Value не экспортируется и не запрещен.

Этот CL улучшает ситуацию с тривиальным изменением пакета fmt: когда мы видим аргумент reflect.Value в качестве аргумента, мы рассматриваем его точно так же, как мы рассматриваем reflect.Value, который мы делаем внутри пакета.
Это означает, что мы всегда печатаем содержимое Value, как если бы это был аргумент Printf.

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