Golang避免代码重复

时间:2017-04-17 17:34:29

标签: go code-duplication

目前我有两个结构。

type One struct {
    Name  string
    Age   int
    ID    int
    Owner string
}

type Two struct {
    ID    int
    Make  string
    Bags  string
    Age   int
    Owner string
}

这些结构映射到数据库中的表,我使用一个接口来提供对数据库和内容的访问。在这种情况下,只根据所有者列出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)
}

我对GO很新,所以我想知道减少代码重复的惯用方法是什么?如果我要添加更多结构,那么它将是不实用的,因为需要重复代码量。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

假设db.client.GetAllinterface{}作为其第二个参数,它可能实际上将其干掉:

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
}

将结果转换为地图有点困难,因为Go缺少泛型,并且您的结构没有可用于连接它们的方法。这是可能的,但至少需要在每种类型上创建一个getID方法,创建一个hasID接口,然后返回map[int]hasID,然后调用者必须将其转换为element(by.cssContainingText('*', 'Test Text'))返回struct类型的值以访问任何其他字段。不是最佳的,但可行的。但是,上述解决方案至少可以让您消除大部分重复代码。

答案 1 :(得分:1)

只是要添加到已接受的答案中,如果您使用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)
    }
}

顺便说一下,如果要控制从数据存储区加载类型OneTwo等的方式,可以让它们实现PropertyLoadSaver接口。