为了账号安全,请及时绑定邮箱和手机立即绑定

Go接口返回类型

Go接口返回类型

Go
aluckdog 2023-05-15 14:54:57
我有一个这样的界面:type ViewInterface interface{    Init() View}type View struct{    Width  int    Height int}所以我从 View 创建了一个新类型type MainView Viewfunc (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() View为什么MianView不一样View?解决这个问题的正确方法是什么?
查看完整描述

2 回答

?
慕码人2483693

TA贡献1860条经验 获得超9个赞

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

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


ViewInterface但真正的问题是和的设计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()

}

然后,View只要MainView它们实现,就可以按照您喜欢的方式进行结构化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 对你的项目必须如何构建有坚定的想法。


查看完整回答
反对 回复 2023-05-15
?
呼如林

TA贡献1798条经验 获得超3个赞

与 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()

  }

}


查看完整回答
反对 回复 2023-05-15
  • 2 回答
  • 0 关注
  • 140 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信