Go工厂方法返回的是接口类型,而不是实现该接口的结构体。

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

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}
}

huangapple
  • 本文由 发表于 2016年1月23日 03:14:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/34954212.html
匿名

发表评论

匿名网友

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

确定