Golang避免代码复制
我目前有两个结构。Golang避免代码复制
type One struct {
Name string
Age int
ID int
Owner string
}
type Two struct {
ID int
Make string
Bags string
Age int
Owner string
}
这些结构映射到表在DB中,我使用的接口,以提供接入到数据库和内容。在这种情况下,只需根据所有者列出One和Two中的数据。
type dbInterface interface {
ListOnesByOwner(owner string) ([]*One, error)
LitsTwosByOwner(owner string) ([]*Two, error)
}
除结构外,列表函数是相同的。
func (db *DB) ListOnes(owner string) ([]*One, error) {
ones = make([]*One, 0)
q := db.NewQuery("One").
Filter("Owner =", owner).
Order("Name")
keys, err := db.client.GetAll(q, &ones)
for i, k := range keys {
ones[i].ID = k.ID
}
return ones, nil
}
func (db *DB) ListTwos(owner string) ([]*Two, error) {
twos = make([]*Two, 0)
q := db.NewQuery("Two").
Filter("Owner =", owner).
Order("Name")
keys, err := db.client.GetAll(q, &twos)
for i, k := range keys {
twos[i].ID = k.ID
}
return twos, nil
}
func main() {
ones, err := DB.ListOnesByOwner(user.ID)
twos, err := DB.ListTwosByOwner(user.ID)
}
我是相当新的去,所以我想知道什么是减少这里看到的代码重复的惯用方法是什么?如果我要添加更多的结构,那么它会很难处理,因为需要大量的代码重复。
感谢您的帮助!
假设db.client.GetAll
需要一个interface{}
作为第二个参数,它看起来,你其实可以干出来:
func (db *DB) dryGet(owner, table string, result interface{}) error {
q := db.NewQuery(table).Filter("Owner =", owner).Order("Name")
keys,err := db.client.GetAll(q, &result)
return err
}
结果转换为一个地图是有点困难,因为围棋缺乏仿制药,而你的结构没有可用于连接它们的方法。这是可能的,但至少需要在每种类型上创建一个方法,创建一个接口,然后返回map[int]hasID
,调用者然后必须将值返回到结构类型以访问任何其他字段。不是最佳的,但可行的。但是,上面的解决方案至少会让你消除重复代码的很大一部分。
只是添加到接受的答案,如果您使用google.golang.org/appengine/datastore您不需要循环的键,除非你想。
从GetAll docs:(重点煤矿)
GETALL运行在给定的情况下查询并返回 匹配查询,以及追加值DST所有键。
所以,你可以在你的两个方法简化为这样的事情:
func (db *DB) ListOnes(owner string) ([]*One, error) {
ones = make([]*One, 0)
q := db.NewQuery("One").
Filter("Owner =", owner).
Order("Name")
if _, err := db.client.GetAll(q, &ones); err != nil {
return nil, err
}
return ones, nil
}
func (db *DB) ListTwos(owner string) ([]*Two, error) {
twos = make([]*Two, 0)
q := db.NewQuery("Two").
Filter("Owner =", owner).
Order("Name")
if _, err := db.client.GetAll(q, &twos); err != nil {
return nil, err
}
return twos, nil
}
这仍是相当多的重复的,所以你可以有办法像在接受的答案,现在推广你的代码,例如:
type dbInterface interface {
ListByType(owner, typ string, dst interface{}) ([]*datastore.Key, error)
}
func (db *DB) ListByType(owner, typ string, dst interface{}) ([]*datastore.Key, error) {
q := db.NewQuery(typ).
Filter("Owner =", owner).
Order("Name")
return db.client.GetAll(q, dst)
}
你也可以使用像这样实现:
func main() {
// ignore keys if you don't need them
ones := []*One{}
if _, err := DB.ListByType(user.ID, "One", &ones); err != nil {
panic(err)
}
// use keys if you need them
twos := []*Two{}
keys, err := DB.ListByType(user.ID, "Two", &twos)
if err != nil {
panic(err)
}
}
顺便说一句,如果你想控制你的类型,如One
和Two
等是如何从数据存储中加载的,你可以让它们实现PropertyLoadSaver接口。
这非常有帮助,谢谢。 – Harry
在我发布我的答案之前,我有一个问题。是'db.client.GetAll'和'inteface {}'的第二个参数吗? – RayfenWindspear
我投票结束这个问题作为题外话,因为这个问题属于https://codereview.stackexchange。com/ –
@PaulHankin他没有要求进行一般的代码审查,他问的是如何使用Go语言的具体问题。对于我来说这似乎合法。 – Adrian