Issue
Using go
and gorm
in a project.
I have created a dao
level to wrap the database operations, each table has its own dao type.
Current code
-
Get
method fromFirstDao
forfirst
table andFirstModel
:func (dao *FirstDao) Get(id uint64) (*model.FirstModel, error) { }
-
Get
method fromSecondDao
forsecond
table andSecondModel
:func (dao *SecondDao) Get(id uint64) (*model.SecondModel, error) { }
What I want to achieve
Wondering is it possible to write a BaseDao
in go, with a single Get()
method, so that I don’t have to write this code 2 times.
This is very easy in Java, but since go is very different, and don’t support real inheritance (I guess), not sure is this possible.
What I have tried
- Define a Model interface, and try to use refection. But failed.
Main reason: inside theGet()
method, it still need an instance of the original specific struct, e.gmodel.FirstModel{}
, I pass it as interfacemodel.Model
, and can’t use it as original type. - struct embedding.
- Googling
Questions
- Is it possible to do this?
- If not, why?
- If yes, how?
Solution
If you’re trying to completely bypass writing a Get()
method for each DAO, your only solution is to return an interface{}
from this method.
However this approach creates two problems :
- You need to manually cast the
interface{}
everywhere. - You are sacrifying type safety.
The solution I think the best, is to share most of the code by using structure embedding, and write lightweight wrappers for each DAO to convert the unsafe interface{}
into a type-safe value.
Example
First create your base DAO with a generic Get()
method.
There is no type generics in Go, so you should return an interface{}
here.
type BaseDAO struct {}
func (*BaseDAO) Get(id uint64) (interface{}, error) {}
Then, for each type of data, create a specific DAO implementation, embedding BaseDAO
:
type FooModel = string
type FooDAO struct {
// Embbeding BaseDAO by not specifying a name on this field
// BaseDAO methods can be called from FooDAO instances
BaseDAO
}
func (foo *FooDAO) Get(id uint64) (FooModel, error) {
// Call the shared Get() method from BaseDAO.
// You can see this just like a `super.Get()` call in Java.
result, _ := foo.BaseDAO.Get(id)
return result.(FooModel), nil
}
Answered By – Arthur Chaloin
Answer Checked By – Jay B. (GoLangFix Admin)