Go接口返回类型
I have an interface like this:
type ViewInterface interface{
Init() View
}
type View struct{
Width int
Height int
}
So I create a new type from View
type MainView View
func (m MainView) Init() MainView{
return MainView{
Width:10,
Height:10,
}
}
then I pass the MainView to the following method:
func Render(views ...ViewInterface){
for _, view := range views {
v := view.Init()
}
}
func main() {
Render(MainView{})
}
But I get this error:
cannot use MainView literal (type MainView) as type ViewInterface in argument to Render: MainView does not implement ViewInterface (wrong type for Init method)
have Init() MainView
want Init() View
Why MianView
is not same as View
? what is the right way to solve this problem?
thanks
我有这样的界面: p>
type ViewInterface界面 {
Init()View
}
type View struct {
宽度int
高度int
}
code> pre>
所以我创建了一个新的 从视图中键入 p>
键入MainView视图
func(m MainView)Init()MainView {
return MainView {
宽度:10,
高度:10,
}
}
code> pre>
然后将MainView传递给以下方法: p>
func Render( views ... ViewInterface){
表示_,视图:=范围视图{
v:= view.Init()
}
}
func main(){
Render(MainView {})\ n}
code> pre>
但出现此错误: p>
不能将MainView文字(类型MainView)用作 在渲染的
参数中输入ViewInterface in
:MainView不实现ViewInterface(Inn方法的类型错误
)
具有Init()MainView
想要Init()视图 p>
为什么 MianView code>与 View code>不同? 解决此问题的正确方法是什么? p>
感谢 p>
div>
GO has different inheritance model comparing to mainstream languages like Java and C#.
Why MianView is not same as View?
Because they are defined differently.
Init
function of MainView
returns MainView
while interface requires to return View
.
Signature of Init
method looks strange, it requires instance of structure because it is structure method and returns new instance of the same structure type.
Try to design interface around logic of your structures instead of their construction/lifetime:
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()
}
}
Because type MainView View
is a "defined type" and "is different from any other type, including the type it is created from.".
Instead you can use a type alias. type MainView = View
.
But really the problem is the design of ViewInterface
and Init()
.
Init()
is written like a class method. Go doesn't have class methods (or, strictly speaking, classes). You create the struct and call methods on it. Simple initialization can be done right then.
view := View{ Width: 10, Height: 10 }
If you want to define a method to initialize the values consistently it would act on an existing struct and return nothing.
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()
Then MainView
can also define Init()
.
type MainView struct {
X int
Y int
}
type (mv *MainView) Init() {
mv.X = 23
mv.Y = 42
}
Because Init()
takes a pointer, to satisfy ViewInterface
you have to pass in pointers.
func main() {
view := View{}
mv := MainView{}
Render(&view, &mv)
}
But what is Render()
doing initializing objects anyway? That should already be done. It should be rendering. Interfaces should be all about common functionality with no regard to how its implemented. The things implementing ViewInterface should already be initialized.
Instead, you might say that a ViewInterface
must have a Render
method.
type ViewInterface interface{
Render()
}
Then View
and MainView
can be structured however you like as long as they implement Render()
.
func (v View) Render() {
fmt.Println("View!")
fmt.Println(v)
}
func (mv MainView) Render() {
fmt.Println("MainView!")
fmt.Println(mv)
}
Then aRender()
can take a list of things which implement ViewInterface
and call Render()
on each of them.
func Render(views ...ViewInterface){
for _, view := range views {
view.Render()
}
}
Initialize them before passing them in. And now there's no need to pass pointers.
func main() {
view := View{}
view.Init()
mv := MainView{}
mv.Init()
Render(view, mv)
}
Finally, Markus suggested in the comments using a package to get something like class methods.
# 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 packages take a little getting used to, Go has firm ideas about how your project must be structured. I suggest this tutorial.