Go 接口返回类型



我有一个这样的界面:

type ViewInterface interface{
Init() View
}
type View struct{
Width  int
Height int
}

所以我从视图创建一个新类型

type MainView View
func (m MainView) Init() MainView{
return MainView{
Width:10,
Height:10,
}
}

然后我将主视图传递给以下方法:

func Render(views ...ViewInterface){
for _, view := range views {
v := view.Init()
}
}
func main() {
Render(MainView{})
}

但是我收到此错误:

不能将 MainView 文本(类型主视图)用作 ViewInterface 类型。 参数来呈现:主视图没有实现视图接口(错误 init 方法的类型)有 init() 主视图想要 init()
视图

为什么MianViewView不一样? 解决这个问题的正确方法是什么?

谢谢

>因为type MainView View是"定义的类型",并且">不同于任何其他类型,包括创建它的类型"。

相反,您可以使用类型别名。type MainView = View.


但真正的问题是ViewInterfaceInit()的设计。

Init()编写得像类方法一样。Go 没有类方法(或者,严格来说,类)。创建结构并对其调用方法。然后可以完成简单的初始化。

view := View{ Width: 10, Height: 10 }

如果要定义一个方法以一致地初始化值,它将作用于现有结构并且不返回任何内容。

type ViewInterface interface{
Init()
}
type View struct{
Width  int
Height int
}
func (v *View) Init() {
v.Width = 10
v.Height = 10
}
view := View{}
view.Init()

然后MainView也可以定义Init()

type MainView struct {
X int
Y int
}
type (mv *MainView) Init() {
mv.X = 23
mv.Y = 42
}

因为Init()需要指针,所以为了满足ViewInterface你必须传入指针。

func main() {
view := View{}
mv := MainView{}
Render(&view, &mv)
}

但是Render()初始化对象到底在做什么呢?这应该已经做到了。它应该是渲染的。接口应该完全是关于通用功能,而不考虑其实现方式。实现 ViewInterface 的东西应该已经初始化了。

相反,您可能会说ViewInterface必须具有Render方法。

type ViewInterface interface{
Render()
}

然后ViewMainView可以按照您喜欢的方式进行结构化,只要它们实现Render().

func (v View) Render() {
fmt.Println("View!")
fmt.Println(v)
}
func (mv MainView) Render() {
fmt.Println("MainView!")
fmt.Println(mv)
}

然后,Render()可以获取实现ViewInterface的事物列表,并对每个事物调用Render()

func Render(views ...ViewInterface){
for _, view := range views {
view.Render()
}
}

在传入之前初始化它们。现在无需传递指针。

func main() {
view := View{}
view.Init()
mv := MainView{}
mv.Init()
Render(view, mv)
}

最后,Markus 在评论中建议使用包来获取类似类方法的东西。

# viewtest/main.go
package main
import(
"log"
"viewtest/view"
)
func main() {
v := view.New()
log.Printf("%#v", v)
}

# viewtest/view/view.go
package view
type View struct {
Width  int
Height int
}
func New() View {
return View{Width: 10, Height: 10}
}

Go包需要一点时间来适应,Go 对你的项目必须如何构建有坚定的想法。我建议本教程。

与Java和C#等主流语言相比,Go具有不同的继承模型。

为什么 MianView 与 View 不一样?

因为它们的定义不同。

InitMainView的函数返回MainView而接口需要返回View

Init方法的签名看起来很奇怪,它需要结构实例,因为它是结构方法并返回相同结构类型的新实例。

尝试围绕结构的逻辑而不是它们的构造/生命周期来设计界面:

type ViewInterface interface{
Render()
}
type MainView View
func (m MainView) Render() {
// do something
}
type AnotherView
func (m AnotherView) Render() {
// do something else
}
func Render(views ...ViewInterface){
for _, view := range views {
view.Render()
}
}

最新更新