具有接收指定接口参数的函数的 Golang 接口
Golang Interface with functions receiving specified Interface args
我正在尝试在 Go 中使用接口以获得两个优势:
- 保护自己不要混淆变量顺序
- 使包彼此独立,所以有一天我可以轻松地替换其中一个包。
在我的特殊情况下,我可以找到解决方法,但我不明白为什么我尝试的方法行不通,这看起来很简单且合乎逻辑。
我就是这样做的。
在一个包(命名处理程序)中,我有一个描述我需要的功能的接口,只是接收 Account
.
的东西
package handlers
type Accounter interface {
AddAccount(a Account)
}
type Account interface {
AccountID() int64
UserID() int64
OtherID() int64
}
在我程序的其他包(名为 accounter)中,我有与接口匹配的功能,以及 Account
接口的定义以避免从第一个包导入此接口。
package accounter
type Account interface {
AccountID() int64
UserID() int64
OtherID() int64
}
func (x *accounter) AddAccount(a Account) {
...
}
但是 go vet
告诉我我不能这样做:
configure_stats_loader.go:109:64: cannot use x (type *accounter.Accounter) as type handlers.Accounter in argument to handlers.AddAccHandler:
*accounter.Accounter does not implement handlers.Accounter (wrong type for AddAccount method)
have AddAccount(accounter.Account)
want AddAccount(handlers.Account)
遇到这种情况我得解决:
- 从其中一个包中导入
Account
界面。
- 定义函数接收标准 go 类型的值,如
(UserID, AccoutID, OtherID int64)
。
在第一种情况下,我在包中失去了独立性,并且在将来我将无法替换 Accounter
接口而不重写一些代码(不是很多代码,但仍然如此),在第二种情况下,如果我' Account
中会有很多类似的方法和很多参数,我可能会不小心混淆变量的顺序。例如不小心将 AccountID
用作 UserID
.
现在的问题是:有什么方法可以兼顾所有优势吗?防止混淆变量顺序并避免从一个包导入到另一个包。
呼应@Marc 的评论,“third-party”包非常适合定义常见类型。这是常见的做法,尤其是在处理 gRPC generated code.
时
同样根据Effective Go保持接口简短:
Interfaces with only one or two methods are common in Go code
因此,避免费力的 getter/setter 定义 - 并专注于更大的操作。所以我建议在你的“类型”包中:
package mydefs
// concrete type: used for Creation and lookup
type Account struct {
ID int64
UserID int64
OtherID int64
}
// abstract interface: keep method list short
type Accounter interface {
Add(a Account) error //
Get(a Account) (Account, error) // use concrete type as a lookup request type
}
我正在尝试在 Go 中使用接口以获得两个优势:
- 保护自己不要混淆变量顺序
- 使包彼此独立,所以有一天我可以轻松地替换其中一个包。
在我的特殊情况下,我可以找到解决方法,但我不明白为什么我尝试的方法行不通,这看起来很简单且合乎逻辑。
我就是这样做的。
在一个包(命名处理程序)中,我有一个描述我需要的功能的接口,只是接收 Account
.
package handlers
type Accounter interface {
AddAccount(a Account)
}
type Account interface {
AccountID() int64
UserID() int64
OtherID() int64
}
在我程序的其他包(名为 accounter)中,我有与接口匹配的功能,以及 Account
接口的定义以避免从第一个包导入此接口。
package accounter
type Account interface {
AccountID() int64
UserID() int64
OtherID() int64
}
func (x *accounter) AddAccount(a Account) {
...
}
但是 go vet
告诉我我不能这样做:
configure_stats_loader.go:109:64: cannot use x (type *accounter.Accounter) as type handlers.Accounter in argument to handlers.AddAccHandler:
*accounter.Accounter does not implement handlers.Accounter (wrong type for AddAccount method)
have AddAccount(accounter.Account)
want AddAccount(handlers.Account)
遇到这种情况我得解决:
- 从其中一个包中导入
Account
界面。 - 定义函数接收标准 go 类型的值,如
(UserID, AccoutID, OtherID int64)
。
在第一种情况下,我在包中失去了独立性,并且在将来我将无法替换 Accounter
接口而不重写一些代码(不是很多代码,但仍然如此),在第二种情况下,如果我' Account
中会有很多类似的方法和很多参数,我可能会不小心混淆变量的顺序。例如不小心将 AccountID
用作 UserID
.
现在的问题是:有什么方法可以兼顾所有优势吗?防止混淆变量顺序并避免从一个包导入到另一个包。
呼应@Marc 的评论,“third-party”包非常适合定义常见类型。这是常见的做法,尤其是在处理 gRPC generated code.
时同样根据Effective Go保持接口简短:
Interfaces with only one or two methods are common in Go code
因此,避免费力的 getter/setter 定义 - 并专注于更大的操作。所以我建议在你的“类型”包中:
package mydefs
// concrete type: used for Creation and lookup
type Account struct {
ID int64
UserID int64
OtherID int64
}
// abstract interface: keep method list short
type Accounter interface {
Add(a Account) error //
Get(a Account) (Account, error) // use concrete type as a lookup request type
}