无需更改接收器即可实现接口

时间:2020-10-17 16:58:14

标签: go

我想定义一个接口,该接口的方法返回一个类型为接口本身的值。

我试图这样定义接口:

type Event interface {
}

type Entity interface {
    ApplyEvent(command Event) (Entity, error)
}

我想通过以下方式使结构实现Entity接口:

type ShoppingList struct {
}

func (list ShoppingList) ApplyEvent(event Event) (ShoppingList, error) {
    // code that changes "list" goes here.
    return list, nil
}

如果我这样做,然后尝试将ShoppingList传递给需要实体的函数,则会出现以下错误:

func main() {
    test(ShoppingList{})
}

func test(e Entity) {
}

Cannot use 'ShoppingList{}' (type ShoppingList) as type Entity. 
Type does not implement 'Entity' 
need method: ApplyEvent(command Event) (Entity, error) 
have method: ApplyEvent(event Event) (ShoppingList, error)
   

我知道我可以这样定义接口和接收器:

type Event interface {
}

type Entity interface {
    ApplyEvent(command Event) error
}

type ShoppingList struct {
}

func (list *ShoppingList) ApplyEvent(event Event) error {
    // code that changes "list" goes here.
    return nil
}

但是我更愿意使用纯函数和不可变数据结构来编写代码。

我想返回更改后的值,而不是使接收方发生变化。

在Go中执行此操作的方式是什么?

1 个答案:

答案 0 :(得分:1)

似乎您可能已经知道这一点。但是以防万一您还没有想到它,您也可以这样写:

type Event interface {
}

type Entity interface {
    ApplyEvent(command Event) (Entity, error)
}

type ShoppingList struct {
}

func (list ShoppingList) ApplyEvent(event Event) (Entity, error) {
    //...
    return list
}

在这里,我做的是相同的return,但我将其作为Entity接口而不是ShoppingList返回。如果稍后将Entity用作购物清单是有意义的,如果我想在代码的后面查看Entity是否是ShoppingList,则可以尝试进行类型断言。

但是,为interface提供一种接口方法,使ShoppingList能够做到其事,是因为它是 Entity 而不是消费者列举所有可能的实体。毕竟,为什么将“事件”应用于“ ShoppingList”的过程中必然会产生另一个“ ShoppingLIst”?它不能生成例如InstacartInvoice吗?当然,在这一点上,我已经超出了您的问题范围。但是,只要接口的具体值的类型与使用者有关,就必须非常努力地使其与该接口的方法有关。就像您使用ApplyEvent一样。