Программно заполнить структуру golang - PullRequest
0 голосов
/ 22 октября 2019

У меня есть файл со многими типами записей данных, которые мне нужно проанализировать в структурах.

Я был бы благодарен за изучение идиоматического способа - если он существует - заполнения структур по записитип. Что-то вроде namedtuple(*fields) конструктора Python.

package main

import (
    "fmt"
    "strconv"
    "strings"
)

type X interface{}

type HDR struct {
    typer, a string
    b        int
}

type BDY struct {
    typer, c string
    d        int
    e        string
}

var lines string = `HDR~two~5
BDY~four~6~five`

func sn(s string) int {
    i, _ := strconv.Atoi(s)
    return i
}

func main() {
    sl := strings.Split(lines, "\n")
    for _, l := range sl {
        fields := strings.Split(l, "~")
        var r X
        switch fields[0] {
        case "HDR":
            r = HDR{fields[0], fields[1], sn(fields[2])} // 1
        case "BDY":
            r = BDY{fields[0], fields[1], sn(fields[2]), fields[3]} // 2
        }
        fmt.Printf("%T : %v\n", r, r)
    }
}

Мне особенно интересно узнать, могут ли строки, отмеченные // 1 и // 2, быть удобно заменены кодом, возможно, своего рода универсальным декодером, который позволяетсама структура для обработки преобразования типов.

1 Ответ

2 голосов
/ 22 октября 2019

Используйте пакет отражает для программной установки полей.

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

type HDR struct {
    Typer, A string
    B        int
}

type BDY struct {
    Typer, C string
    D        int
    E        string
}

Создайте карту имен для типа, связанного с именем:

var types = map[string]reflect.Type{
    "HDR": reflect.TypeOf((*HDR)(nil)).Elem(),
    "BDY": reflect.TypeOf((*BDY)(nil)).Elem(),
}

Для каждой строки создайте значениетипа с использованием карты types:

for _, l := range strings.Split(lines, "\n") {
    fields := strings.Split(l, "~")
    t := types[fields[0]]
    v := reflect.New(t).Elem()
    ...
}

Зацикливание полей в строке. Получите значение поля, преобразуйте строку в тип значения поля и установите значение поля:

    for i, f := range fields {
        fv := v.Field(i)
        switch fv.Type().Kind() {
        case reflect.String:
            fv.SetString(f)
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
            n, _ := strconv.ParseInt(f, 10, fv.Type().Bits())
            fv.SetInt(n)
        }
    }

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

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

...