https://play.golang.org/p/A_9CbQ6z_lC
How to check if struct implements given interface by self?
You could iterate over the fields and inspec tthe mto see if they implement the interface:
https://play.golang.org/p/ZA_QjEVzAsq
However, this is not the best way to design such functionality. It is probably better to keep track of whether or not Init was called using a bool member in your struct, set that when Init is called and check that to prevent calling Init twice.
Why do you need to distinguish between the two?
(What's the higher-level problem you're trying to solve?)
@bcmills I'm trying to implement inheritance like c++, Init same as constructor, if not distinguish, Init of embedded struct will be called many times. Like @beoran said , using a bool member is a way, but need add member to each struct, has other way to do this?
@bcmills @beoran The original description is incorrect, has modified.
I would advise against trying to implement inheritance like C++. Go is not C++.
@ianlancetaylor Sorry, but that is not very helpful. I am slowly working on a GUI library in Go (https://gitlab.com/beoran/ebsgo/tree/master/zori), and for GUIs, C++ish virtual inheritance is extremely useful. With Go this can be done relatively easy by using a struct with an embedded interface.
On to answering the question now, in Go, normally we do not inherit the constructor. Rather, the constructor is always a function, normally named New() or NewSomething( ) .
Secondy, to enable virtual inheritance, make in interface with all methods that have to be inherited and include that interface as an embedded field in all structs that you would like to inherit those methods. Then in the constructor for these structs, set that interface to the correct object, normally the struct itself. You can see a short GUI-ish example here:
https://play.golang.org/p/a_wYXw7poX1
package main
import (
"fmt"
)
type Drawer interface {
Draw()
}
type Colorer interface {
Color() string
}
type Widget interface {
Drawer
Colorer
// Probably will need an event handler as well, omitted for brevity
}
type BasicWidget struct {
Widget
Label string
}
func (bw BasicWidget) Color() string {
return "red"
}
func (bw BasicWidget) Draw() {
// Call virtual color method
fmt.Printf("%s %s:\n", bw.Widget.Color(), bw.Label)
}
func NewBasicWidget(label string) *BasicWidget {
bw := &BasicWidget{Label: label}
// Needed to enable virtual inheritance
bw.Widget = bw
return bw
}
type Label struct {
*BasicWidget
}
func NewLabel(label string) *Label {
lab := &Label{NewBasicWidget(label)}
lab.Widget = lab
}
func (lab Label) Color() string {
return "green"
}
type DropDown struct {
*BasicWidget
Options []string
}
func (dd DropDown) Color() string {
return "blue"
}
func (dd DropDown) Draw() {
// Reuse parent draw method
dd.BasicWidget.Draw()
for _, option := range dd.Options {
fmt.Printf(" -%s\n", option)
}
}
func NewDropDown(label string, options []string) *DropDown {
dd := &DropDown{BasicWidget: NewBasicWidget(label), Options: options}
// Needed to enable virtual inheritance
dd.Widget = dd
return dd
}
type Gui struct {
Widget
Widgets []Widget
}
func NewGui() *Gui {
gui := &Gui{}
// Needed to enable virtual inheritance
// gui.Widget = gui
return gui
}
func (gui *Gui) Append(widget Widget) *Gui {
gui.Widgets = append(gui.Widgets, widget)
return gui
}
func (gui Gui) Draw() {
fmt.Printf(",______________,\n")
for _, widget := range gui.Widgets {
widget.Draw()
}
fmt.Printf(".______________.\n")
}
func main() {
gui := NewGui()
gui.Append(NewBasicWidget("basic 1")).Append(NewDropDown("dropdown 1", []string{"option 1", "option 2"})).Append(NewLabel("label 1"))
gui2 := NewGui()
gui2.Append(NewBasicWidget("basic 2")).Append(NewDropDown("dropdown 2", []string{"option x", "option y"}))
gui.Append(gui2)
gui.Draw()
}
If this example is not clear, please ask again and I will explain it more in detail.
Edit: improved the example so it really needs virtual inheritance, previously it could also work with static inheritance.
@beoran, I studied the problem of how to map C++ inheritance to Go for quite some time, and your solution is very similar to the one I came up with, with one minor difference: I passed the overridden methods as an argument to the New function rather than assigning to an exported field. (That allows you to simulate overrides of protected methods, since the value returned by the New function doesn't need to implement every method of the interface passed to New.)
While that approach does seem to work, it does not generally result in an idiomatic Go API. In my experience, there is usually a different — and equally usable — way to structure the API that meshes better with the rest of the Go ecosystem.
Any any rate, @shihaonan369, it seems that you have an answer to the underlying use-case, if not to the question you actually asked. If you want C++-style inheritance, don't check whether the struct implements the interface; instead, define a separate interface for the methods to be overridden.
@bcmills , well yes, that would work too. Also, I know that usually there is a more Go idiomatic way to do it, but for classic GUI libraries, for example, C++ style inheritance is extremely useful, especially if you want to allow users to extend your library with custom widgets.
@beoran, thank you for your answer and patience.
Considering the following code:
https://play.golang.org/p/uQqfFgXEIWt
The Component as base struct to implements some features such as scope and so on. My original idea is using type tags, like this:
`component:{scope: "singleton"}`
type App struct {
}
Using type tags can flatten component, without multilevel inheritance means can avoid some problem. but golang doesn't support it now, hopefully that can be supported in the future. For now i using field tags to do the same thing, like this:
type Component struct {
}
type App struct {
Component `scope:"singleton"`
}
Then call NewAndInitComponent(), children will be created in sequence and initialized in reverse, that make sure dependencies to be initialized in correct.
Now there is a bug that has comment.
// BUG: remove it will cause Init() of App to be called two times.
func (a *TestApp) Init() error {
fmt.Println("Init TestApp")
a.C.PrintSetting()
return nil
}
I'm ready to limit layers of inheritance to fix up the bug, any suggestions?
Seeing your play example, I'd say you are making things more complicated then they have to be. There is no need to use reflection or type tags this much for OOP and using OO design patterns in GO language.
For example, in Go language a singleton is commonly implemented as a package level variable, protected by mutexes if threading is an issue. I would never use struct annotations for that. And secondly as I stated before, Go uses NewXXX() both for constructor and initialization, rolled in one. Normally, there is no separate inherited Init function like in other languages.
I think that you are probably familiar with other languages, and you now want to bring that experience to Go. But the idioms used in Go are different from other languages, so you will have to adapt a bit to that. I'd recommend to read a bit more idiomatic Go code, such as the source code of the Go compiler itself, to find out more about how to write Go without unneeded complexity.
Or take a look at this:
https://github.com/svett/golang-design-patterns
It explains how you can implement the classic "gang of four" design patterns in Go.
@beoran
After a few days of learning and trying, I realized using oop in golang is more or less confusing, such as calling method with nil receiver. May be the best way is forget it, learn and using the design pattern in golang. I will take look given repository, thanks a lot.
Most helpful comment
I would advise against trying to implement inheritance like C++. Go is not C++.