6

我有一个这样的界面:

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

但我得到这个错误:

不能在 Render 的参数中使用 MainView 文字(类型 MainView)作为 ViewInterface 类型:MainView 没有实现 ViewInterface(Init 方法的类型错误)
有 Init() MainView
想要 Init() 视图

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

谢谢

4

2 回答 2

6

与 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()
  }
}
于 2018-12-09T04:24:55.553 回答
6

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

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


但真正的问题在于ViewInterfaceand的设计Init()

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

然后 aRender()可以列出实现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 对如何构建项目有坚定的想法。我建议这个教程

于 2018-12-09T04:31:19.600 回答