我在 Typescript 中有一个代码,它使用通用存储库,与以下示例类似。 ts游乐场
// Model class that have generic ID type
class Model<T = number | string> {
id?: T;
createdAt?: Date;
updatedAt?: Date;
}
interface CrudRepository<T extends Model<ID>, ID = number | string> {
getAll(): Array<T>
findByID(id: ID): T
}
// GenericRepository class with generic model type, that have method for interact with DB (CRUD)
class GenericRepository<T extends Model<ID>, ID = number | string> implements CrudRepository<T, ID> {
// dbContext
constructor(mockData: Array<T>) {
this.mockData = mockData
}
mockData: Array<T>
getAll = (): Array<T> => this.mockData
findByID = (id: ID): T => this.mockData.find((v) => v.id = id) || ({} as T) // Need to get ID values
}
// User model
class User extends Model<number> {
name?: string
constructor(id: number, name: string) {
super();
this.id = id;
this.name = name;
}
}
// User service
class UserService {
repo: CrudRepository<User, number>
constructor(repo: GenericRepository<User, number>) {
this.repo = repo
}
getAll = (): User[] => this.repo.getAll();
findByID = (id: number): User => this.repo.findByID(id);
}
function main() {
const mockUsers = [new User(1, 'Person A'), new User(2, 'Person B')];
const repo = new GenericRepository(mockUsers);
const serv = new UserService(repo);
console.log(`All: ${JSON.stringify(serv.getAll())}`);
console.log(`User 1: ${JSON.stringify(serv.findByID(1))}`);
}
main();
结果应该是:
[LOG]: "All: [{"id":1,"name":"Person A"},{"id":2,"name":"Person B"}]"
[LOG]: "User 1: {"id":1,"name":"Person A"}"
目前我的新项目想使用Go语言。据我所知,我们可以在 Go 中使用
T ~struct{}
,如下代码所示。
https://goplay.tools/snippet/Mk7A8JByRQA
package main
import (
"fmt"
"time"
)
func main() {
repo := GenericRepository[User, int64]{
mockData: mockUsers,
}
users := repo.GetAll()
fmt.Println(users[0].ID)
fmt.Println(users)
}
type Model[TID int64 | string] struct {
ID TID
CreatedAt time.Time
UpdateAt time.Time
}
type User struct {
Model[int64]
// Name string // Remove it to run without error
}
type GenericRepository[T ~struct{ Model[ID] }, ID int64 | string] struct {
mockData []T
}
func (r GenericRepository[T, ID]) GetAll() []T {
return r.mockData
}
func (r GenericRepository[T, ID]) FindByID(id ID) T {
// Error v.ID undefined (type T has no field or method ID)
// for _, v := range r.mockData {
// if v.ID == id {
// return v
// }
// }
// Error v.Model undefined (type T has no field or method Model)
// for _, v := range r.mockData {
// if v.Model.ID == id {
// return v
// }
// }
return *new(T)
}
var mockUsers = []User{
User{Model: Model[int64]{ID: 1}},
User{Model: Model[int64]{ID: 2}},
}
但是当我向 User struct
User does not satisfy ~struct{Model[int64]} (User missing in ~struct{main.Model[int64]})
添加更多字段时出现错误,并且我也无法与 T 内的值交互,例如 ID 或 Model。
type User struct {
Model[int64]
Name string
}
您的目标似乎是编写一个与 Person 和 Developer 值一起使用的 Greet 函数。
为了实现目标,请声明一个具有 Greet 所需功能的接口。 Greet 函数需要有名称的东西:
type Namer interface {
Name() string
}
使用该界面编写问候语。
func Greet(a, b Namer) {
fmt.Println(a.Name(), "Hello", b.Name())
}
定义满足接口的Person类型:
type Person struct {
name string
}
func (p *Person) Name() string { return p.name }
func NewPerson(name string) *Person { return &Person{name: name} }
使用 embedding 创建具有人员的开发人员。 Developer 类型满足 Namer 接口,因为嵌入的 Person 字段上的 Name 方法被提升为 Developer 类型。
type Developer struct {
*Person
skill string
}
func NewDeveloper(name, skill string) *Developer {
return &Developer{Person: NewPerson(name), skill: skill}
}
创建一些人员和开发者值并让他们打招呼:
a := NewPerson("Person A")
b := NewPerson("Person B")
dev := NewDeveloper("The dev", "Fullstack")
Greet(a, b)
Greet(dev, a)
你不能。 Go 在设计上没有继承。
Dylan Bourque 有一个很棒的演讲比我更好地解释了它,但基本上嵌入不是继承 - 虽然你可以使用嵌入结构的方法和字段,但你没有“is-a”关系,这在大多数支持继承的语言中都是有问题的。
你的函数有无用的泛型:
function Greet<T extends Person>(a: T, b: T) {
console.log(a.name + " Hello " + b.name)
}
因为如果你有继承,那有什么区别
function Greet(a: Person, b: Person) {
console.log(a.name + " Hello " + b.name)
}
?通常,最好考虑一下你想要做什么,而不是尝试在问题中已经定义不明确的类型系统中表达某些内容。
如果您需要类似
<T extends Object>
之类的东西,也许类型约束就是您正在寻找的东西 - 但从您的示例中很难说它首先不应该有泛型。 另请参阅 Go 常见问题解答中的