首页 文章

转到界面返回类型

提问于
浏览
3

我有这样的界面:

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)作为Render参数中的类型ViewInterface:MainView没有实现ViewInterface(Init方法的错误类型)有Init()MainView想要Init()视图

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

谢谢

2 回答

  • 6

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

    相反,你可以使用type alias . 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 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 .

  • 4

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

    为什么MianView与View不一样?

    因为它们的定义不同 .

    Init 函数 MainView 返回 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()
      }
    }
    

相关问题