Go中空接口的最佳实践?

Go中空接口的最佳实践?,go,interface,Go,Interface,我正在学习空接口。我发现,虽然也有很多关于空接口的含义和工作方式的Stackoverflow解释,但关于何时/为什么使用它们、何时避免、考虑事项是什么以及选择使用它们的优缺点的最佳实践的信息很少 在Go聊天室中,我读到了一些关于尽可能避免使用空接口的讨论,但是没有适当的参数。其他人自豪地回答说,他们的代码设计中没有空接口 我最感兴趣的是库和框架的使用(打算被其他人重用/扩展) 现在我正在阅读一个包含相关库的框架代码库,在很多地方都有emtpy接口。其中一些让我困惑,我想知道是否所有的用法都是合理

我正在学习空接口。我发现,虽然也有很多关于空接口的含义和工作方式的Stackoverflow解释,但关于何时/为什么使用它们、何时避免、考虑事项是什么以及选择使用它们的优缺点的最佳实践的信息很少

在Go聊天室中,我读到了一些关于尽可能避免使用空接口的讨论,但是没有适当的参数。其他人自豪地回答说,他们的代码设计中没有空接口

我最感兴趣的是库和框架的使用(打算被其他人重用/扩展)


现在我正在阅读一个包含相关库的框架代码库,在很多地方都有emtpy接口。其中一些让我困惑,我想知道是否所有的用法都是合理的。像框架提供的“用户管理”和
AppConfiguration
UserPreferences
等都是空接口。在代码中(靠近数据库层),用户的电子邮件在技术上被视为用户首选项。在接口定义中更具体一点不是更好吗?

空命名接口在Go中没有意义,因为与C#等其他语言不同,例如,任何类型(C#中的类)如果与接口签名匹配,都可以强制转换到特定接口。因此,在Go中,“类”(结构类型)不需要从接口继承(例如,在定义类型时声明接口)

那么你的问题的答案是:

Go中空接口的最佳实践不是在Go中定义命名的空接口

更新:由于下面的评论,我改变了主意,并且我同意,为了在IDE中编写文档和更快地导航,使用空命名接口的用例可能有限

在Go聊天室中,我读到了一些关于尽可能避免使用空接口的讨论,但是没有适当的参数。其他人自豪地回答说,他们的代码设计中没有空接口

最大的问题是你输了所有的打字;例如,假设我有一个函数,我想对各种类型的数字进行运算,所以我写:

func AddOne(n interface{}) int64 {
    switch nn := n.(type) {
        case int:
            return nn + 1
        case int8:
            return nn + 1
        // ... etc...
    }
}
但是如果我将0.42(float64)传递给这个函数,或者传递字符串
“asd”
,该怎么办?如果函数将接受一个int64(
func AddOne(n int64)int64
),那么我们将在编译时得到一个关于这个的警告,但是使用
interface{}
您将不会得到任何东西,因为所有内容都是有效的

最好是在运行时处理这个问题,然后使用panic()或返回错误;这显然比编译时错误要清楚得多

这是迄今为止最大的缺点


我必须查看那些
AppConfiguration
UserPreferences
函数的详细信息,但使用空接口有一些很好的理由;例如,当您希望接受某个自定义结构,然后使用反射根据某些外部数据在该结构上设置值时。这基本上就是
encoding/json
等包所做的,但它也常用于解析一些配置文件,等等

这听起来像是
AppConfiguration
UserPreferences
可能适合这一点,因为库/框架不知道您的应用程序配置需要什么设置,或者用户的首选项是什么。但就像我说的,没有细节很难确定

另一个用例是当您真的想要接受多种类型时;将参数传递给SQL查询是一个常见的示例,即
fmt.Printf()



一般来说,避免使用
interface{}
可能是最好的,但是如果你发现自己在这样做的时候已经竭尽全力了,那么最好只使用
interface{}
而不用打字。

我想问题是关于命名为空接口的,比如
typeuserpreferences interface{}
。谢谢@martin tournoij!对于libs+框架,我所指的只是打算被他人重用和扩展的代码。有一些命名的空接口,也有类似于
func(a*App)DefaultUserPreferences()接口{}
的东西,它返回
nil
。但是,用户首选项应包括数据库中所需的电子邮件。命名/键入空界面的优点之一是,您可以将方法附加到它们@ArnoldSchrijver;一般来说,在没有
接口{}
的情况下编写一些通用的用户身份验证库需要一些努力(尽管这也不是不可能的,正如我所做的那样)。但就像我说的,很难说清楚;可能有一些特性或考虑因素使接口难以使用。@MartinTournoij据我所知,我们不能将方法“附加”到命名接口,只能附加到“结构类型”。如果我错了,请纠正我?您可以将方法附加到任何类型@AlexanderTrakhimenok(
type x string
,我已经做了很多次),但实际上我现在不确定接口类型。看起来您不能:
名为的接收方类型无效(名为接口类型)
,所以我想“空的命名接口在Go中没有意义”是错误的,除非它有意义。此外,Go中没有类,也没有继承。不清楚您是否试图在C#或Go的上下文中使用这些术语。出于同样的原因,您可能会使用任何其他基类型的命名类型:Documentation。如果您的litmus测试是stdlib。还有很多其他的。i、 谢谢你的链接,我真的很感激。虽然链接1和链接2会导致测试代码,但如果您想测试依赖于它的行为,显然可以使用空的命名接口。关于“著名的例子”,为了论证,它是一个好的、有效的例子,在研究了代码之后,我同意为了文档的目的使用它可能是有意义的