重构函数使其可以在Go中的类型之间重用

时间:2013-09-01 17:36:44

标签: refactoring 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
  }
}

这很好用,但现在我还需要初始化包含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
  }
}

重构此代码以使其更干燥的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

您显示的代码违反DRY原则。实现Loader接口的代码(我拒绝为您使用的 javaism 编写)类型FooListBarList只共享一行 - 范围语句。否则它们是特定类型的。

由于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)