英文:
Go factory method returns type interface, not the struct which implements the interface
问题
我正在尝试创建一个工厂方法,该方法返回一个实现某个接口的结构体的构造函数。
以下是我正在使用的模式的示例代码:
// 泛型接口
type Foo interface {
Bar() string
}
type FooConstructor func(name string) Foo
// 实现Foo接口的结构体
type RealFoo struct {
Name string
}
func (f *RealFoo) Bar() string {
return f.Name
}
func NewRealFoo(name string) Foo {
return &RealFoo{Name: name}
}
// 工厂方法返回某个FooConstructor
func FooFactory() FooConstructor {
// 基于某些逻辑,返回某个Foo构造函数
return NewRealFoo
}
func main() {
ff := FooFactory()
f := ff("baz")
fmt.Println(f.Bar())
fmt.Println(f.Name)
}
当我尝试访问在接口中未定义的结构体字段时,会出现错误:
f.Name undefined (type Foo has no field or method Name)
我认为问题在于我的构造函数func NewRealFoo(name string) Foo
的返回类型是接口,而不是*RealFoo
。但是为了将其用作工厂方法的类型FooConstructor
,返回类型必须是Foo
接口。
我该如何修改代码以便访问字段f.Name
?
英文:
I am trying to create a factory method that returns a constructor for a struct that implements some interface.
Here is some sample code that illustrates the pattern I'm using.
// Generic Interface
type Foo interface {
Bar() string
}
type FooConstructor func(name string) Foo
// A struct that implements Foo
type RealFoo struct {
Name string
}
func (f *RealFoo) Bar() string {
return f.Name
}
func NewRealFoo(name string) Foo {
return &RealFoo{Name: name}
}
// Factory method to return some FooConstructor
func FooFactory() FooConstructor {
// based on some logic, return some Foo constructor
return NewRealFoo
}
func main() {
ff := FooFactory()
f := ff("baz")
fmt.Println(f.Bar())
fmt.Println(f.Name)
}
http://play.golang.org/p/0RzXlIGAs8
When I try and access a field on my struct that is not defined in the interface, I get an error:
f.Name undefined (type Foo has no field or method Name)
I believe the problem is that my constructor, func NewRealFoo(name string) Foo
has the interface as the return type, instead of *RealFoo
. But in order to use it as a type FooConstructor
for the factory method, the return type must be the Foo
interface.
How can I fix my code so that I can access the field f.Name
?
答案1
得分: 2
实际上,你正在返回RealFoo
对象,但作为Foo
的实现。
要获取RealFoo
结构的字段,可以使用类型断言:
f.(RealFoo).Name
或者,为了避免出现恐慌(panic),如果它不是RealFoo
类型:
if realFoo, ok := f.(RealFoo); ok {
_ := realFoo.Name
}
或者使用switch
语句处理Foo
的所有或部分可能的类型:
switch rf := f.(type) {
case realFoo:
_ := rf.Name // rf 是 realFoo 类型
case unrealFoo:
_ := rf.ImaginaryName // rf 是 unrealFoo 类型
case surrealFoo:
_ := rf.SurrealName // rf 是 surrealFoo 类型
default:
// rf 不是以上任何一种类型
}
如果你愿意修改工厂构造函数,也可以从NewRealFoo
返回一个RealFoo
,而不是Foo
。由于它实现了该接口,因此在任何需要Foo
的地方仍然可以使用它。这就是在NewRealFoo
中返回RealFoo
的做法,即在返回Foo
的函数中返回RealFoo
。
func NewRealFoo(name string) RealFoo {
return &RealFoo{Name: name}
}
英文:
You are actually returning the RealFoo
object, but as an implementation of Foo
.
To get the field of the RealFoo
struct, use a type assertion:
f.(RealFoo).Name
or, to avoid panic if it's not a RealFoo
:
if realFoo, ok := f.(RealFoo); ok {
_ := realFoo.Name
}
or a switch over all or some of the possible types of Foo
switch rf := f.(type) {
case realFoo:
_ := rf.Name // rf is a realFoo
case unrealFoo:
_ := rf.ImaginaryName // rf is an unrealFoo
case surrealFoo:
_ := rf.SurrealName // rf is a surrealFoo
default:
// rf is none of the above types
}
You could also return a RealFoo
from NewRealFoo
, instead of a Foo
, if you are willing to modify your factory constructor. It will still be valid to use anywhere a Foo
is expected, since it implements that interface. That's what you are doing that in NewRealFoo
, when returning a RealFoo
in a function returning Foo
.
func NewRealFoo(name string) RealFoo {
return &RealFoo{Name: name}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论