实现具有可变参数的接口方法

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

Implementing interface method with variable arguments

问题

我从简单的接口开始:

type Module interface {
	Init(deps ...interface{}) error
}

我以为实现会很简单,因为这个方法应该匹配任意数量的提供的参数。这就是我最终得到的代码,我认为TestModule实现了Module接口。

type TestModule struct {
}

func (m *TestModule) Init(str string) error {
	return nil
}

但是当我想将TestModule传递给任何需要Module的函数时,我得到了这个错误:
>无法将module(类型*TestModule)作为参数传递给testFunc中的类型Module:

func testFunc(module Module) {

}

编辑:有没有最佳实践来实现这种行为?

英文:

I started with the simple interface:

type Module interface {
	Init(deps ...interface{}) error
}

I thought, the implementation will be really simple, because this method should match any number of provided arguments. This is what I end up with this code, thinking, the TestModule implements the Module interface.

type TestModule struct {
}

func (m *TestModule) Init(str string) error {
	return nil
}

But when I want to pass the TestModule to any function that wants Module, I get this error:
>cannot use module(type *TestModule) as type Module in argument to testFunc:

func testFunc(module Module) {

}

Edit: is there any best practice to implement this kind of behaviour?

答案1

得分: 6

这不是实现接口的方式:

func (m *TestModule) Init(str string) error {
    return nil
}

你困惑的地方在于“因为这个方法应该匹配任意数量的提供的参数”,这是一种语言特性,允许调用者使用可变数量的参数调用该方法(参见这里https://stackoverflow.com/questions/10128771/what-does-mean-when-next-to-a-parameter-in-a-go-function-declaration)。要实现它,你需要实现相同的签名,即... interface{}

所以明确一点,'任意数量的提供的参数'只适用于调用方法,这并不意味着你可以使用任意类型的任意参数集来实现该方法并具有相同的定义。定义表明调用者将传入一个实现interface{}的可变数量的项目。

“有没有最佳实践来实现这种行为?”

我不知道有没有。我认为常见的做法是将传入的类型放宽为interface{}... interface{},然后在方法内部检查集合。例如,如果Module接口的定义是Init(deps interface{}) error,那么你可以在测试模块中这样实现它:

func (m *TestModule) Init(deps interface{}) error {
    str := deps.(string)
    return nil
}

如果你想要可变长度的参数,你只需要在方法中添加一个for range结构来解包值或进行一些边界检查。我不能确定这是否是你的应用程序中的最佳实践,因为我认为这取决于你从单个方法签名中获得多少价值。它会增加额外的样板代码并带来一些轻微的性能损失。

英文:

This doesn't implement the interface;

func (m *TestModule) Init(str string) error {
    return nil
}

Where your confusion arises is in "because this method should match any number of provided arguments" this is a language feature which lets the caller invoke the method with a variable number of arguments (see here https://stackoverflow.com/questions/10128771/what-does-mean-when-next-to-a-parameter-in-a-go-function-declaration). To implement it you need to implement the same signature meaning ... interface{}.

So to be clear, the 'any number of provided arguments' is for calling the method only, that doesn't mean you can implement the method with any set of arguments of any types and it will have the same definition. The definition states there will be a variable number of items implementing interface{} passed in by the caller.

"is there any best practice to implement this kind of behaviour?"

Not that I know of. I think the common practice would be to relax the type being passed in to interface{} or the ... interface{} and then inspect the collection inside the method. For example, if the Module interface had it's definition as Init(deps interface{}) error then you could implement it in test module like this;

func (m *TestModule) Init(deps interface{}) error {
      str := deps.(string)
      return nil
}

If you want variable length of args, you would just have to add a for range construct into the method to unbox the value or do some bounds checking. I can't speak to whether or not this would be a good practice in your application because I think it depends on how much value you get from having a single method sig. It adds extra boiler plate code and has some minor performance penalty.

huangapple
  • 本文由 发表于 2015年10月13日 23:40:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/33106960.html
匿名

发表评论

匿名网友

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

确定