In Go can I return a struct that meets an interface without access to that interface?

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

In Go can I return a struct that meets an interface without access to that interface?

问题

我认为最好的解释方法是通过示例,所以这里是代码:

package main

import (
	"fmt"
)

// Greeter greets with a Greeting.
type Greeter interface {
	Greet() Greeting
}

// A Greeting has a string representation.
type Greeting interface {
	String() string
}

type Hello struct{}

// Hello greets by returning itself...
func (h *Hello) Greet() Greeting {
	return h
}

// ...because Hello also has a string representation.
func (h *Hello) String() string {
	return "Hello"
}

// But Go says Hello doesn't implement Greeter.
func main() {
	var g interface{} = &Hello{}
	g, ok := g.(Greeter)
	fmt.Println(ok)
}

这将打印出false。你可以运行并尝试它:https://play.golang.org/p/A_2k_ku_Q2

在我的实际情况中,结构体HelloGreeterGreeting的接口位于不同的包中,它们彼此不导入,我希望保持这种方式。也许我对Go中的接口有些理解上的问题,但是在阅读了这么多相关内容之后,我仍然无法理解其中的关键点。你们有什么指导意见吗?也许对于这个问题还有其他的方法?谢谢!

英文:

I think the best way to explain this is by example, so here it is:

package main

import (
	"fmt"
)

// Greeter greets with a Greeting.
type Greeter interface {
	Greet() Greeting
}

// A Greeting has a string representation.
type Greeting interface {
	String() string
}

type Hello struct {}

// Hello greets by returning itself...
func (h *Hello) Greet() *Hello {
	return h
}

// ...because Hello also has a string representation.
func (h *Hello) String() string {
	return "Hello"
}

// But Go says Hello doesn't implement Greeter.
func main() {
	var g interface{} = &Hello{}
	g, ok := g.(Greeter)
	fmt.Println(ok)
}

This prints false. You can run and play with it: https://play.golang.org/p/A_2k_ku_Q2

In my real case the struct Hello and the interfaces for Greeter and Greeting are in different packages that do not import each other and I wanted to keep it that way. I'm perhaps missing some understanding of interfaces in Go but after reading so much about it I still can't put my finger on it. Would you guys have any pointers for me? Maybe another approach for the problem? Thanks!

答案1

得分: 11

根据评论中所述,问题在于一旦你的接口具有以下签名:

type Greeter interface {
    Greet() Greeting
}

任何有效的实现都必须将Greeting作为返回类型。

但是,正如文档所示,你不需要给接口命名:

https://golang.org/ref/spec#Interface_types

为了能够实现你所需的功能,你可以直接在返回值中声明接口,而不给它命名。

// Greeter greets with anything that has a String() method
type Greeter interface {
    Greet() interface{ String() string }
}

然后,你的HelloGreet()函数可以这样写:

// Hello greets by returning itself...
func (h *Hello) Greet() interface{ String() string } {
   return h
}

在这里可以找到一个修改后的示例代码:

https://play.golang.org/p/HteA_9jFd4

英文:

As stated in the comments, problem here is once your interface has this signature:

type Greeter interface {
    Greet() Greeting
}

The any valid implementation must use exactly Greeting as the return type.

But, as the documentation shows, you don't need to give the interface a name:

https://golang.org/ref/spec#Interface_types

In order to be able to implement what you need, you might declare the interface directly in the return value, without giving it a name.

// Greeter greets with anything that has a String() method
type Greeter interface {
    Greet() interface{ String() string }
}

Then your Greet() function for Hello can do this:

// Hello greets by returning itself...
func (h *Hello) Greet() interface{ String() string } {
   return h
}

Find here a modified playground showing the working example:

https://play.golang.org/p/HteA_9jFd4

huangapple
  • 本文由 发表于 2017年8月6日 05:12:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/45526476.html
匿名

发表评论

匿名网友

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

确定