2017-04-03 18:31
浏览 89


In the current project we use Go and MongoDB via mgo driver. For every entity we have to implement DAO for CRUD operations, and it's basically copy-paste, e.g.

func (thisDao ClusterDao) FindAll() ([]*entity.User, error) {
    session, collection := thisDao.getCollection()
    defer session.Close()
    result := []*entity.User{} //create a new empty slice to return 
    q := bson.M{}
    err := collection.Find(q).All(&result)
    return result, err

For every other entity it's all the same but the result type.

Since Go has no generics, how could we avoid code duplication?

I've tried to pass the result interface{} param instead of creating it in the method, and call the method like this:


but the collection.Find().All() method need a slice as the input, not just interface:

[restful] recover from panic situation: - result argument must be a slice address

Then I tried to make this param result []interface{}, but in that case it's impossible to pass []*entity.User{}:

cannot use []*entity.User literal (type []*entity.User) as type []interface {} in argument to thisDao.GenericDao.FindAll

Any idea how could I implement generic DAO in Go?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dqxyh48864
    dqxyh48864 2017-04-03 19:22

    You should be able to pass a result interface{} to your FindAll function and just pass it along to mgo's Query.All method since the argument's would have the same type.

    func (thisDao ClusterDao) FindAll(result interface{}) error {
        session, collection := thisDao.getCollection()
        defer session.Close()
        q := bson.M{}
        // just pass result as is, don't do & here
        // because that would be a pointer to the interface not
        // to the underlying slice, which mgo probably doesn't like
        return collection.Find(q).All(result)
    // ...
    users := []*entity.User{}
    if err := dao.FindAll(&users); err != nil { // pass pointer to slice here
    点赞 评论