我有一个函数,它从一个值数组的数组初始化一个结构数组。这就是我目前正在做的事情:
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
}
}
这很好用,但现在我还需要初始化包含Bars和Baz的BarLists和BazLists。而不是在我的代码中洒出相同的片段,这些片段看起来像这样:
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
}
}
重构此代码以使其更干燥的正确方法是什么?
答案 0 :(得分:1)
您显示的代码不违反DRY原则。实现Loader
接口的代码(我拒绝为您使用的 javaism 编写)类型FooList
和BarList
只共享一行 - 范围语句。否则它们是特定类型的。
由于Go没有泛型,不以泛型方式编写类型的专用版本没有直接的方法(模数差的选择,如一切都是interface{}
等等和/或使用反射将代码放慢10倍。)
答案 1 :(得分: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)