如何正确使用泛型来定义数据访问对象的实体和键。

huangapple go评论160阅读模式
英文:

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

huangapple
  • 本文由 发表于 2022年7月20日 00:07:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/73040241.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定