英文:
How do I properly use generics for an entity and key for a data access object
问题
我对Go中的泛型还不太熟悉,但我可以尝试帮你翻译一下你的代码和错误信息。
首先,你的代码中定义了一个模板类型Model[K]
,它有一个类型为K
的ID字段。然后,你定义了一个CrudTemplate[E Model[K], K any]
类型,其中E
是一个模型类型,它有一个类型为K
的ID字段。
在你的user.go
文件中,你定义了一个User
结构体,它嵌入了Model[uuid.UUID]
类型,并且有一些其他的字段。
接着,在你的user_test.go
文件中,你尝试创建一个UserRepositoryImpl
实例,并调用FindById
方法。
然而,编译失败,并显示以下错误信息:
无法将model.User用作类型interface{},因为该类型未实现约束'interface{}',因为该类型未包含在类型集合中('{Model[K], {E -> model.User, K -> uuid.UUID}}')
根据错误信息,似乎是因为model.User
类型没有实现约束interface{}
,导致编译失败。
希望这些信息对你有帮助。如果你需要更多的帮助,请告诉我。
英文:
I am very new to generics in Go and am trying to implement a basic entity and data access object with the idea that the entity has a type E
and a key of type K
. The type E
is also constrained as a model type having a field of ID of type K
.
template.go
type Model[K any] struct {
ID K
}
type CrudTemplate[E Model[K], K any] struct {
}
func (c *CrudTemplate[E, K]) FindById(ctx context.Context, id K) (*E, error) {
tx := getTx(ctx)
e := &E{}
tx = tx.Find(e, id)
if tx.Error != nil {
return nil, tx.Error
} else {
return e, nil
}
}
When I try and do an implementation and test as follows...
user.go
type User struct {
Model[uuid.UUID]
RealmID uuid.UUID
FamilyName string
GivenName string
}
type UserRepository struct {
CrudTemplate[User, uuid.UUID]
}
... and the following test ...
user_test.go
func TestUserRepositoryImpl_Find(t *testing.T) {
unit := &UserRepositoryImpl{}
unit.FindById(ctx, id)
}
... it fails compilation with the following message.
> Cannot use model.User as the type interface{} Type does not implement constraint 'interface{}' because type is not included in type set ('{Model[K], {E -> model.User, K -> uuid.UUID}}')
Any advice would be appreciated.
答案1
得分: 1
不嵌入struct
,而是使用一个你的存储库将实现的interface
。
开始你的CRUD
操作,通用的读取(查找)方法可能如下所示:
type Repository[K, E any] interface {
Find(context.Context, K) (E, error) // 通过键搜索存储库
}
这个接口的一个具体实现:
type UserRepository struct {
// ... 数据库细节
}
func (ur *UserRepository) Find(ctx context.Context, id uuid.UUID) (User, error) {
return User{
RealmID: id,
FamilyName: "Smith",
GivenName: "Bib",
}, nil
}
使用方法:
var ur Repository[uuid.UUID, User] // 实例化`Repository`类型
ur = &UserRepository{}
u, err := ur.Find(ctx, uuid.UUID{1, 2, 3})
工作示例:https://go.dev/play/p/j9cN8vy9675
英文:
Rather than embedding a struct
- I think you simply want an interface
that your repository will implement.
To begin your CRUD
operations, the generic read (lookup) method would look something like this:
type Repository[K, E any] interface {
Find(context.Context, K) (E, error) // search repo by key
}
A particular implementation of this interface:
type UserRepository struct {
// ... db details
}
func (ur *UserRepository) Find(ctx context.Context, id uuid.UUID) (User, error) {
return User{
RealmID: id,
FamilyName: "Smith",
GivenName: "Bib",
}, nil
}
And to use:
var ur Repository[uuid.UUID, User] // type instantiate `Repository`
ur = &UserRepository{}
u, err := ur.Find(ctx, uuid.UUID{1, 2, 3})
Working example: https://go.dev/play/p/j9cN8vy9675
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论