Go接口返回类型

时间:2018-12-09 03:54:19

标签: go go-interface

我有这样的界面:

type ViewInterface interface{
    Init() View
}

type View struct{
    Width  int
    Height int
}

所以我从View创建一个新类型

type MainView View

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

然后将MainView传递给以下方法:

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

func main() {
  Render(MainView{})
}

但是我得到这个错误:

  

不能使用MainView文字(MainView类型)作为ViewInterface类型   Render的参数:MainView不实现ViewInterface(错误   方法的类型)
  具有Init()MainView
  想要Init()查看

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

谢谢

2 个答案:

答案 0 :(得分:6)

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

  

为什么MianView与View不同?

因为它们的定义不同。

Init的{​​{1}}函数返回MainView,而接口要求返回MainView

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

尝试围绕结构的逻辑而非结构/寿命设计接口:

Init

答案 1 :(得分:4)

因为type MainView View"defined type""is different from any other type, including the type it is created from."

您可以使用type aliastype 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 suggested in the comments使用包来获取类似类方法的内容。

# 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对于必须如何构造项目具有明确的想法。 I suggest this tutorial