Как я могу использовать интерфейс для нормализации различных структур? - PullRequest
0 голосов
/ 03 февраля 2020

Я использую Go для сбора различных характеристик perfmon и хотел бы привести их к чему-то похожему на модель EAV, но изо всех сил пытаюсь обернуть мой мозг вокруг того, как это сделать sh.

с учетом приведенных примеров структур:

type Win32_PerfFormattedData_Counters_ProcessorInformation struct {
    Name                    string
    C1TransitionsPersec     uint64
    C2TransitionsPersec     uint64
    C3TransitionsPersec     uint64
    PercentUserTime         uint64
    PercentInterruptTime    uint64
    PercentPrivilegedTime   uint64
    PercentC1Time           uint64
    PercentC2Time           uint64
    PercentC3Time           uint64
}
type Win32_PerfFormattedData_Tcpip_NetworkAdapter struct {
    Name                        string
    BytesSentPersec             uint64
    BytesReceivedPersec         uint64
    OffloadedConnections        uint64
    PacketsOutboundDiscarded    uint64
    PacketsOutboundErrors       uint64
    PacketsReceivedDiscarded    uint64
    PacketsReceivedErrors       uint64  
}

Я бы хотел нормализовать их до:

type Counter struct {
    counter_category        string
    counter_name            string
    counter_instance        string
    counter_value           uint64
}

Используя reflect Я смог прийти с этим:

func pivot(cpu_info *[]Counter, cpu Win32_PerfFormattedData_Counters_ProcessorInformation, category string) {
    e := reflect.ValueOf(&cpu).Ellem()
    for i := 0; i < e.NumField(); i++ {
        f_name := e.Type().Field(i).Name
        f_value := e.Field(i).Interface()
        if f_name != "Name" {
            c := Counter {
                counter_category: category,
                counter_name: f_name,
                counter_instance: cpu.Name,
                counter_value: f_value.(uint64),
            }
            *cpu_info = append(*cpu_info,c)
        }
    }
}

Тем не менее, у меня есть 17 категорий счетчиков, которые я собираю, и я не верю, что написание 17 из этих функций - лучшая идея (если это не так, и я рад быть исправлено).

Я дошел до этого благодаря функции, которая использует интерфейс, но я просто не знаю, нахожусь ли я на правильном пути:

func pivot_counter(counter interface{}, counter_info *[]Counter) {
    var counter_category string
    switch t := counter.(type) {
    case []Win32_PerfFormattedData_Counters_ProcessorInformation:
        counter_category = "Processor"
        fmt.Printf("%T\r\n",t)
    case []Win32_PerfRawData_Tcpip_NetworkAdapter:
        counter_category = "Network Adapter"
        fmt.Printf("%T\r\n",t)
    default:
        counter_category = "Unknown"
        fmt.Printf("%T\r\n", t)
    }
}

Но вот где я Я застрял, потому что я все еще в месте, где мне нужно будет создать 17 различных операторов case с 17 различными блоками логики "pivot" c в этих случаях. Я знаю, что делаю что-то не так. По сути, я пытаюсь написать функцию, которая будет принимать структуру / интерфейс, определять тип через утверждение типа, а затем использовать этот объект для итерации полей структуры, чтобы преобразовать их в однородный формат. Где я go откуда я сейчас нахожусь?

1 Ответ

1 голос
/ 03 февраля 2020

Определите ваш интерфейс:

type CounterMaker interface {
    MakeCounter() Counter
}

Теперь, для каждого имеющегося у вас типа, сделайте так, чтобы он поддерживал CounterMaker:

type Win32_PerfFormattedData_Counters_ProcessorInformation struct {
    ...
}

func (value Win32_PerfFormattedData_Counters_ProcessorInformation) MakeCounter() Counter {
    ... code to turn "value" into a counter ...
    return result
}

Повторите для других типов.

(Показанный выше интерфейс не обязательно является правильным ; выберите тот, который соответствует вашей ситуации.)

Теперь, если у вас есть какая-то функция, для которой требуется экземпляр Counter, вы можете сделать ее, или перед вызовом, или внутри. Например:

func Increment(running *Counter, newstuff CounterMaker) {
    inc := CounterMaker.MakeCounter()
    // maybe double check that the running counter matches w/ "inc"
    running.counter_value += inc.counter_value
}

Если вы работали с этим примером - который, опять же, может не быть правильным способом сделать это - теперь вы можете передать значение Win32_PerfFormattedData_Counters_ProcessorInformation в качестве Второй аргумент Increment, потому что он реализует MakeCounter и поэтому квалифицируется как CounterMaker.

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