Go:工厂函数返回指针和interface{}类型

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

Go: factory returning pointer and interface{} type

问题

考虑以下工厂代码:Go playground

type TypeA struct {
    placeholder int
}

func NewTypeA() *TypeA {
    return new(TypeA)
}

func main() {
  factory := make(map[string]func() interface{})
  factory["TypeA"] = NewTypeA
}

这给我返回了以下错误:cannot use NewTypeA (type func() *TypeA) as type func() interface {} in assignment,这很明显。

我原以为interface{}可以与指针匹配。

我找到了这个解决方案:Go playground

type Entity interface {}

type TypeA struct {
    Entity
    placeholder int
}

func NewTypeA() Entity {
    return new(TypeA)
}

func main() {
  var tmp interface{}
  factory := make(map[string]func() Entity)
  factory["TypeA"] = NewTypeA
  tmp = factory["TypeA"]()
  log.Println(reflect.TypeOf(tmp))
}

这给我返回了预期的类型*TypeA
是否有其他方法可以直接使用interface{}类型而不是一个“愚蠢”的接口(Entity)来实现这个?

英文:

Consider the following factory: Go playground

type TypeA struct {
    placeholder int
}

func NewTypeA() *TypeA {
    return new(TypeA)
}

func main() {
  factory := make(map[string]func() interface{})
  factory["TypeA"] = NewTypeA
}

This gives me the following error: cannot use NewTypeA (type func() *TypeA) as type func() interface {} in assignment which is pretty clear.

I thought that interface{} was able to be matched with a pointer.

I found this solution: Go playground

type Entity interface {}

type TypeA struct {
    Entity
    placeholder int
}

func NewTypeA() Entity {
    return new(TypeA)
}

func main() {
  var tmp interface{}
  factory := make(map[string]func() Entity)
  factory["TypeA"] = NewTypeA
  tmp = factory["TypeA"]()
  log.Println(reflect.TypeOf(tmp))
}

Which gives me the expected type *TypeA.
Is there an other way to do this using the interface{} type directly instead of a "dumb" interface (Entity)?

答案1

得分: 3

我不认为你完全理解interface{}是什么,因此你试图错误地使用它。

正如这篇文章所述:

空接口类型interface{}是一个非常令人困惑的概念。

我建议你阅读那篇文章,然后再仔细看看你想要做的事情。

interface{}不是任何其他类型的占位符,它本身就是一个类型

因此,如果你创建一个以返回interface{}类型的函数作为键的映射,那么函数就需要返回该类型。不能返回指针、整数或其他任何类型。

虽然你可以将任何类型的值赋给一个接口,包括指针类型,但你不能将其他类型用作interface{}类型的替代品。

看起来你想要实现的目标是创建一个可以返回任意类型值的函数映射。你只能通过设计函数的方式间接实现这一点。你需要在函数中使用interface{}类型,将要返回的值赋给它,然后返回该接口。但是你必须返回interface{}类型,而不是int、string、*TypeA或其他任何类型。

英文:

I don't think you fully understand what an interface{} is and thus are trying to use it incorrectly.

As stated in this article:

> The interface{} type, the empty interface, is the source of much
> confusion.

I'd recommend that you read that article and then have another look at what you are trying to do.

An interface{} is not a placeholder for any other type, it's a type itself.

So if you create a map that takes functions that return interface{} as keys then that's the type the functions needs to return. Not a pointer or int or anything else.

While you can assign a value of any type to an interface, including pointer types, you can't use other types in place of an interface{} type.

It seems that what you are trying to accomplish is have a map with functions that can return a value of any type. You can only do that indirectly by designing your functions differently. You'd have to use an interface{} type in the function, assign the value you want to return to it and then return the interface{}. But you have to return type interface{} and not type int or string or *TypeA or whatever.

答案2

得分: 1

在你的第二个例子中,NewTypeA() 返回的是 Entity 而不是 *TypeA,因此与 NewTypeA() 返回 interface{} 的解决方案没有任何区别,这使得 Entity 类型完全是不必要的/多余的:

type TypeA struct {
    placeholder int
}

func NewTypeA() interface{} {
    return new(TypeA)
}

func main() {
    factory := make(map[string]func() interface{})
    factory["TypeA"] = NewTypeA

    tmp := factory["TypeA"]()
    fmt.Printf("%T", tmp)
}

输出结果(在 Go Playground 上尝试):

*main.TypeA

保持 *TypeA 返回类型

如果你希望 NewTypeA() 工厂函数仍然返回 *TypeA,你可以通过在 factory 映射中放置一个匿名包装函数来实现:

func NewTypeA() *TypeA {
    return new(TypeA)
}

func main() {
    factory := make(map[string]func() interface{})
    factory["TypeA"] = func() interface{} { return NewTypeA() }

    tmp := factory["TypeA"]()
    fmt.Printf("%T", tmp)
}

再次输出结果(在 Go Playground 上):

*main.TypeA
英文:

In your 2nd example NewTypeA() returns Entity not *TypeA, so it is no different from a solution where NewTypeA() would return interface{} which renders the Entity type completely needless/redundant:

type TypeA struct {
	placeholder int
}

func NewTypeA() interface{} {
	return new(TypeA)
}

func main() {
	factory := make(map[string]func() interface{})
	factory["TypeA"] = NewTypeA

	tmp := factory["TypeA"]()
	fmt.Printf("%T", tmp)
}

Output (try it on the Go Playground):

*main.TypeA

Keeping the *TypeA return type

For convenience if you want your NewTypeA() factory function to still return *TypeA, you can do so by putting an anonymous wrapper function in your factory map:

func NewTypeA() *TypeA {
	return new(TypeA)
}

func main() {
	factory := make(map[string]func() interface{})
	factory["TypeA"] = func() interface{} { return NewTypeA() }

	tmp := factory["TypeA"]()
	fmt.Printf("%T", tmp)
}

Output again (Go Playground):

*main.TypeA

huangapple
  • 本文由 发表于 2015年5月27日 16:19:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/30476861.html
匿名

发表评论

匿名网友

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

确定