我在一个包中有一个结构体,它上面有耗时的方法,而且通过它的工厂函数构造也很耗时。因此,在依赖于这个其他结构的包中,我希望能够在创建后使用假工厂函数和假结构对其进行测试。由于结构是通过工厂函数构造的,我想伪造工厂函数并在测试期间将替代工厂函数传递到我的结构中。
昂贵的包的一个例子是:
package expensive
import "fmt"
type myStruct struct{}
func (m *myStruct) DoSomething() {
fmt.Println("In Do something")
}
func (m *myStruct) DoSomethingElse() {
fmt.Println("In do something else")
}
// CreateInstance is expensive to call
func CreateInstance() *myStruct {
return &myStruct{}
}
Run Code Online (Sandbox Code Playgroud)
我使用它的主包看起来像这样:
package main
import "play/expensive"
func main() {
thing := structToConstruct{expensive.CreateInstance}
thing.performAction()
}
type myInterface interface {
DoSomething()
}
type structToConstruct struct {
factoryFunction func() myInterface
}
func (s *structToConstruct) performAction() {
instance := s.factoryFunction()
instance.DoSomething()
}
Run Code Online (Sandbox Code Playgroud)
但是,此代码抱怨错误:
.\main.go:6: 不能在字段值中使用昂贵的.CreateInstance(类型 func() *expensive.myStruct) 作为类型 func() myInterface
然而,*expensive.myStruct确实实现了 myInterface 接口,所以我不明白为什么 Go 抱怨这个设置的类型安全。
在@jmaloney 指导之后,我意识到我可以在我的主要方法中像这样包装我的函数:
wrapper := func() myInterface {
return expensive.CreateInstance()
}
thing := structToConstruct{wrapper}
Run Code Online (Sandbox Code Playgroud)
然后这可以工作,但我仍然不明白为什么当函数期望返回该接口的实例时我不能使用实现接口的结构,尤其是当此修复程序不需要类型断言/转换时它只是调用底层工厂函数。
编辑:从那以后,我遇到了将其添加到语言中的建议。该提议被拒绝:
getInstance 需要返回 myInterface
package main
import "fmt"
func main() {
var function func() myInterface
function = getInstance
newSomething := function()
newSomething.doSomething()
}
type myInterface interface {
doSomething()
}
type myStruct struct{}
func (m *myStruct) doSomething() {
fmt.Println("doing something")
}
func getInstance() myInterface {
return &myStruct{}
}
Run Code Online (Sandbox Code Playgroud)
然而, *expensive.myStruct 确实实现了 myInterface 接口,所以我不明白为什么 Go 抱怨这个设置的类型安全。
在那种情况下,您不是在处理 Go 的接口,而是在处理结构的类型签名。
当您第一次使用factoryFunction func() *myFunctionfactoryFunction声明结构时,现在总是需要匹配声明的签名。