Go 当将变量分配给任何具有相同签名的接口时,为什么不将设计标记为错误

Go 当将变量分配给任何具有相同签名的接口时,为什么不将设计标记为错误,go,Go,我刚刚开始学习围棋,我的大部分背景都来自Java和Ruby 我只是想知道,在我的示例中,为什么Go语言设计器在实现接口时故意设计为不指定接口类型。因此,如果有人意外地尝试将对象分配给与签名匹配的接口,但不打算实现该接口,那么这将导致出现错误,并且无法在编译时捕获 您可以尝试以下方法: “隐式满足”接口(类型不需要显式声明它们实现它们的接口)的一个优点是可以在事后创建接口。您可以在不同的包中看到几种具有相同方法的类型,并决定通过调用指定该方法的新接口来编写一个可以接受其中任何一种方法的函数 此外,

我刚刚开始学习围棋,我的大部分背景都来自Java和Ruby

我只是想知道,在我的示例中,为什么Go语言设计器在实现接口时故意设计为不指定接口类型。因此,如果有人意外地尝试将对象分配给与签名匹配的接口,但不打算实现该接口,那么这将导致出现错误,并且无法在编译时捕获

您可以尝试以下方法:

“隐式满足”接口(类型不需要显式声明它们实现它们的接口)的一个优点是可以在事后创建接口。您可以在不同的包中看到几种具有相同方法的类型,并决定通过调用指定该方法的新接口来编写一个可以接受其中任何一种方法的函数

此外,Go的接口方法允许您在现有包中编写类型行为的抽象,而无需修改原始包。我想到的第一个例子是net/http包中的文件接口:

type File interface {
    io.Closer
    io.Reader
    io.Seeker
    Readdir(count int) ([]os.FileInfo, error)
    Stat() (os.FileInfo, error)
}
它表示可以由http.FileServer提供服务的文件。通常它是一个os.文件,但它可以是满足接口的任何东西。例如,我认为有人制作了一个实现,它使用zip存档提供文件

由于net/http包是在标准库中定义的,因此可以显式声明os.File实现http.File,但这会使os包依赖于net/http包。这是一个循环依赖关系,因为net/http依赖于操作系统

在基于继承的语言中,尝试这样做的人可能会放弃使用接口,并使http.FileServer要求所有文件都是os.File的子类。但这将是一种痛苦,因为他们不需要任何os.文件的实现;它们只是从它继承来满足类型系统

OP中的示例之所以有效,是因为方法名称选择不当。一个正方形的计算方法应该返回什么结果还不清楚。它的面积?它的周界?是对角线吗?如果方法名为CalculateArea,这将是名为AreaCalculator的接口中单个方法的惯用名称,则不可能混淆AreaCalculator和MathExpression。

隐式满足接口的一个优点(类型不需要显式声明它们实现它们的接口)接口可以在事后创建。您可以在不同的包中看到几种具有相同方法的类型,并决定通过调用指定该方法的新接口来编写一个可以接受其中任何一种方法的函数

此外,Go的接口方法允许您在现有包中编写类型行为的抽象,而无需修改原始包。我想到的第一个例子是net/http包中的文件接口:

type File interface {
    io.Closer
    io.Reader
    io.Seeker
    Readdir(count int) ([]os.FileInfo, error)
    Stat() (os.FileInfo, error)
}
它表示可以由http.FileServer提供服务的文件。通常它是一个os.文件,但它可以是满足接口的任何东西。例如,我认为有人制作了一个实现,它使用zip存档提供文件

由于net/http包是在标准库中定义的,因此可以显式声明os.File实现http.File,但这会使os包依赖于net/http包。这是一个循环依赖关系,因为net/http依赖于操作系统

在基于继承的语言中,尝试这样做的人可能会放弃使用接口,并使http.FileServer要求所有文件都是os.File的子类。但这将是一种痛苦,因为他们不需要任何os.文件的实现;它们只是从它继承来满足类型系统


OP中的示例之所以有效,是因为方法名称选择不当。一个正方形的计算方法应该返回什么结果还不清楚。它的面积?它的周界?是对角线吗?如果方法名为CalculateArea,这将是名为AreaCalculator的接口中单个方法的惯用名称,则不可能混淆AreaCalculator和MathExpression。

此方法的一个好处是依赖项倒置。在具有静态类型系统的典型语言中,从实现到接口都具有源代码级依赖关系。这意味着您不能单独部署它们。使用隐式接口,您没有源代码级依赖关系,实现模块可以在没有包含接口的模块的情况下部署/开发/构建。这为您提供了通常为动态类型系统保留的灵活性。

这种方法的一个好处是依赖项反转。在具有静态类型系统的典型语言中,从实现到接口都具有源代码级依赖关系。这意味着您不能单独部署它们。使用隐式接口,您没有源代码级依赖关系,实现模块可以在没有包含接口的模块的情况下部署/开发/构建。这为您提供了通常为动态类型系统保留的灵活性。

Go使用隐式接口,这意味着如果类型具有接口所需的所有功能,它将实现接口。请注意,您不必在代码中声明该类型实现接口(如在Java中)

这种语言设计有好有坏的后果:

  • 类型可以意外地实现接口(这发生在您的示例中)。事实上,这种情况很少发生,所以在我看来,这不是一个大问题
  • 如果代码中没有接口声明,您就不知道您的类型实现了哪些接口。这个问题可以通过使用好的IDE来解决
  • 您可以轻松创建适配器和类似的设计模式
  • 您可以轻松创建m