我应该使用标准库中的接口还是编写自己的接口?

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

Should I embed interface from standard library or write my own?

问题

Go语言的标准库中有一些常见的接口,例如 io.Closer

type Closer interface {
    Close() error
}

如果我想在我的代码中定义一个具有 Close 方法的接口,我应该像这样嵌入 io.Closer 吗:

type example interface {
    io.Closer

    // ... 其他一些函数或嵌入类型
}

还是我只需定义函数本身,如下所示:

type example interface {
    Close() error

    // ... 其他一些函数或嵌入类型
}

对此有什么最佳实践吗?

英文:

There are some common interfaces in Go's standard library, e.g, the io.Closer:

type Closer interface {
	Close() error
}

If I would want to define an interface in my code that has a Close method, would I embed io.Closer like this:

type example interface {
    io.Closer

    // ... some other functions or embedded types
}

or would I just define the function itself like:

type example interface {
    Close() error

    // ... some other functions or embedded types
}

Is there any best practice for this?

答案1

得分: 2

对于这种常见且简单的接口,我肯定会嵌入标准库中的接口(例如io.Closerio.Readerio.ByteReader)。

但并非所有的接口类型都适合嵌入。通常情况下,应该在需要的地方定义接口。嵌入其他包(包括标准库)中定义的任何接口都存在一个问题,即如果这些接口发生了变化或扩展,可能无法隐式实现它们。

包的“所有者”(定义者)可能会更改它(例如通过添加新方法进行扩展),并正确更新所有实现它的类型,以便包在外部继续工作,但显然包的所有者不会更新你的实现。

例如,reflect.Type接口类型在Go 1.0中没有Type.ConvertibleTo()方法,它是在Go 1.1中添加的。同样的事情可能会发生:标准库中的接口可能会在未来的Go版本中被修改或扩展,导致你现有的代码无法实现它们。

小型、常见的接口和“其他”接口有什么区别?正如Go的谚语所说:“接口越大,抽象性越弱”。像io.Closerio.Reader这样的小型接口捕捉了一个微小但重要的功能。它们是如此常见,几乎“每个”库都试图实现它们,每个实用函数都建立在它们之上。我从不指望它们会改变。如果有理由改变/扩展它们,它们将被作为新接口添加,而不是像更大的接口那样,抽象性更难以准确捕捉。它们更有可能随着时间的推移而改变/演变。

英文:

For such common and simple interfaces I would definately embed the one from the standard lib (such as io.Closer, io.Reader and io.ByteReader).

But not any interface type. In general interfaces should be defined where they are needed. Embedding any interface defined in other packages (including the standard library) has the danger of failing to implicitly implement them if they are changed or extended.

The "owner" (definer) of the package may change it (e.g. extend it with a new method) and properly update all its types implementing it, so the package can continue to work from the outside, but obviously the package owner will not update your implementations.

For example the reflect.Type interface type had no Type.ConvertibleTo() method back in Go 1.0, it was added in Go 1.1. The same thing may happen: interfaces in the standard lib may get altered or extended in future Go versions, resulting in your existing code failing to implement them.

What's the difference between small, common interfaces and the "rest"? The bigger the interface, the weaker the abstraction – so goes the Go proverb. Small interfaces like io.Closer and io.Reader capture a tiny yet important functionality. They are so common, "every" library tries to implement them, every utility functions build upon them. I don't ever expect them to change. If there will be a reason to change / extend them, they will be rather added as new interfaces. Not like bigger interfaces where abstraction is harder to capture accurately. They have a better chance to change / evolve over time.

huangapple
  • 本文由 发表于 2022年1月17日 06:21:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/70734655.html
匿名

发表评论

匿名网友

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

确定