0

我有一个函数,它从一个值数组的数组中初始化一个结构数组。这就是我目前的做法:

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 和 Bazs 的 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
  }
}

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

4

2 回答 2

1

您显示的代码违反 DRY 原则。实现类型接口的代码Loader(我拒绝编写你使用的javaismFooList )并且BarList只共享一行 - range 语句。否则它们是特定类型的。

由于 Go 没有泛型,因此没有直接的方法如何不以泛型方式编写类型专用版本(模数不佳的选择,例如一切都是等等。和/或使用反射将代码减慢 10 倍。)interface{}

于 2013-09-01T17:57:07.740 回答
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)
于 2013-09-01T23:34:20.627 回答