Как получить базовую ценность от рефлексии. Знать в голанге?
Итак, я нашел код, который помогает мне начать работу с отражением в 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?
Ответы
Ответ 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
.
Это, возможно, потрясающее изменение, но я думаю, что это действительно улучшилось и не стало больше перерыва, чем многие другие хитрости, которые мы сделали для форматирования вывода из этого пакета.