2013-09-01 3 views
0

У меня есть функция, которая инициализирует массив структур из массива массива значений. Вот как я это делаю в данный момент:Функция рефакторирования для повторного использования между типами в Go

type Loadable interface { 
    Load([]interface{}) 
} 

type FooList struct { 
    Foos []*Foo 
} 

func (fl *FooList) Load(vals []interface{}) { 
    fl.Foos = make([]*Foo, len(vals)) 
    for i, v := range vals { 
    foo := &Foo{} 
    foo.Load(v.([]interface{})) 
    fl.Foos[i] = foo 
    } 
} 

Это работает просто отлично, но теперь мне нужно инициализировать BarLists и BazLists, которые содержат Бары и Bazs. Вместо того, чтобы брызгать тот же фрагмент кода на протяжении моего кода, все выглядеть следующим образом:

type BarList struct { 
    Bars []*Bar 
} 

func (fl *BarList) Load(vals []interface{}) { 
    fl.Bars = make([]*Bar, len(vals)) 
    for i, v := range vals { 
    bar := &Bar{} 
    bar.Load(v.([]interface{})) 
    fl.Bars[i] = bar 
    } 
} 

Что такое правильный способ реорганизовать этот код, чтобы сделать его более DRY?

ответ

1

Код, который вы показываете , не нарушает принцип СУХОЙ. Код, реализующий интерфейс Loader (я отказываюсь писать javaism, который вы использовали) для типа FooList и BarList разделяет только одну строку - оператор диапазона. В противном случае они зависят от типа.

Как Go не имеет дженерики, нет никакого прямого способа, как не записи типа специализированные версии в родового образом (по модулю плохой выбор, как все это interface{} и т.д., и/или замедляя код 10 раз с помощью отражения)

+0

Угадайте, что я все еще привык к тому, что у вас нет дженериков. Резка и склеивание такого количества кода кажется неправильным, но похоже, что это подходящий способ сделать это. Благодаря! – Bill

0

Простейшим я могу придумать с помощью отражения было бы что-то вроде этого (не проверено):.

import "reflect" 

// example_of_type should be an instance of the type, e.g. Foo{} 
// returns slice of pointers, e.g. []*Foo 
func Load(vals []interface{}, example_of_type interface()) interface{} { 
    type := reflect.TypeOf(example_of_type) 
    list := reflect.MakeSlice(type.PtrOf().SliceOf(), len(vals), len(vals)) 
    for i, v := range vals { 
    bar := reflect.New(type) 
    bar.Interface().(Loadable).Load(v.([]interface{})) 
    list.Index(i).Set(bar) 
    } 
    return list.Interface() 
} 

Вы бы использовать его как:

fl.Foos = Load(vals, Foo{}).([]*Foo) 
fl.Bars = Load(vals, Bar{}).([]*Bar) 
Смежные вопросы