I am fairly new to Go and I have been doing OOP for a long time. Now, I understand that inheritance is done via composition but ... I'd like to send a specialization in a function expecting a generalization as such:
package main
import (
"fmt"
)
type A struct {
ONE int
}
type B struct {
A
ANOTHER int
}
func main() {
fmt.Println("Hello, playground")
a := A{1}
b := B{a, 2}
fmt.Println(a.ONE)
fmt.Println(b.ANOTHER)
takeA(&b)
}
func takeA(a *A) {
fmt.Println(a.ONE)
}
Sure, I can do takeA(&b.A) but it defeats the hierarchy I am trying to set up as some A fields/method could be shadowed in B.
Is there a way around this? Or should I create a dumb interface such as:
package main
import (
"fmt"
)
type A struct {
ONE int
}
func (a A) getOne() int{
return a.ONE
}
type B struct {
A
ANOTHER int
}
type HasOne interface {
getOne() int
}
func main() {
fmt.Println("Hello, playground")
a := A{1}
b := B{a, 2}
fmt.Println(a.ONE)
fmt.Println(b.ANOTHER)
takeA(b)
}
func takeA(a HasOne) {
fmt.Println(a.getOne())
}
There is no inheritance in Go. Composition doesn't give you dynamic dispatch (which is usually implied when 'polymorphism' and 'inheritance' are used in the same paragraph): the embedded method call always happens on the embedded field as a receiver, not on the container type it is embedded into.
Related
I understood that casting is being implemented in go using type assertion.
I'm trying to cast an object which is an instance of a struct that implements an interface.
My Code:
package main
import "fmt"
type Base interface {
Merge(o Base)
}
type Impl struct {
Names []string
}
func (i Impl) Merge (o Base) {
other, _ := o.(Impl)
i.Names = append(i.Names, other.Names...)
}
func main() {
impl1 := &Impl{
Names: []string{"name1"},
}
impl2 := &Impl{
Names: []string{"name2"},
}
impl1.Merge(impl2)
fmt.Println(impl1.Names)
}
Which outputs this:
[name1]
I expect the output to be:
[name1, name2]
Why this casting doesn't work? After debugging this it seems like that the other variable is empty.
You need to use a pointer method to modify the receiver's build.
func (i *Impl) Merge (o Base) {
other, _ := o.(*Impl)
i.Names = append(i.Names, other.Names...)
}
Playground: https://play.golang.org/p/7NQQnfJ_G6A
I'm trying to convert an interface dynamically back to it's original struct but I am having issues accessing attributes of the struct after the conversion.
Take this code for example.
package main
import (
"fmt"
"log"
)
type struct1 struct {
A string
B string
}
type struct2 struct {
A string
C string
}
type struct3 struct {
A string
D string
}
func main() {
s1 := struct1{}
s1.A = "A"
structTest(s1)
s2 := struct2{}
s2.A = "A"
structTest(s2)
s3 := struct3{}
s3.A = "A"
structTest(s3)
}
func structTest(val interface{}) {
var typedVal interface{}
switch v := val.(type) {
case struct1:
fmt.Println("val is struct1")
case struct2:
fmt.Println("val is struct2")
case struct3:
fmt.Println("val is struct3")
default:
log.Panic("not sure what val is.")
}
fmt.Println(typedVal.A)
}
I would like to be able to pass in one of 3 known struct types into my function. Then figure out which struct type was passed in to type assert it. Finally I want to be able to access like attributes.
Basically I want to have some basic inheritance in my structs, but so far it seems that it is not possible to do this in go. I saw some posts mentioning inheritance using an interface, but my structs have no methods so I'm not sure how I would use an interface.
Is something like this possible in go?
I would like to be able to pass in one of 3 known struct types into my function. Then figure out which struct type was passed in to type assert it. Finally I want to be able to access like attributes.
You can use type assertions to do exactly that. Basic idea is, in any case of the type switch just use type assertion to get a concrete instance of the corresponding type and then you can call whatever properties that you wish.
Take a look at the following example
package main
import (
"fmt"
)
type test1 struct {
A, B string
}
type test2 struct {
A, C string
}
func testType(val interface{}) {
switch val.(type) {
case test1:
t := val.(test1)
fmt.Println(t.B)
break
case test2:
t := val.(test2)
fmt.Println(t.C)
break
}
}
func main() {
t1, t2 := test1{B: "hello"}, test2{C: "world"}
testType(t1)
testType(t2)
}
Playground
Function structTest(val interface{}) in your code seems to be loosely typed. You pass it an untyped argument and expect it will satisfy some condition (will have field A), it looks strange in any typed language.
Using an interface this kind of polymorphism, in Go, to my mind, can be expressed something like
package main
import (
"fmt"
"log"
)
type A string
type HasA interface {
PrintA()
}
func (a A) PrintA() { fmt.Println(a) }
type struct1 struct {
A
B string
}
type struct2 struct {
A
C string
}
type struct3 struct {
A
D string
}
func main() {
s1 := struct1{}
s1.A = "A"
structTest(s1)
s2 := struct2{}
s2.A = "A"
structTest(s2)
s3 := struct3{}
s3.A = "A"
structTest(s3)
}
func structTest(val HasA) {
switch val.(type) {
case struct1:
fmt.Println("val is struct1")
case struct2:
fmt.Println("val is struct2")
case struct3:
fmt.Println("val is struct3")
default:
log.Panic("not sure what val is.")
}
val.PrintA()
}
Playground
I have two types, B and C, which share all methods, but implement one of them differently. I would like to express this by having a parent type A, containing the implementations of the shared methods, and embedding A in B and C. (Don't Repeat Yourself!) The snag is that the method that differs between B and C is called in many of the shared methods. What's the idiomatic way to structure such code?
My current implementation looks essentially like this (https://play.golang.org/p/RAvH_hBFDN; based on an example by Dave Cheney):
package main
import (
"fmt"
)
type Legger interface {
Legs() int
}
type Cat struct {
Name string
L Legger
}
// Cat has many methods like this, involving calling c.L.Legs()
func (c Cat) PrintLegs() {
fmt.Printf("I have %d legs.\n", c.L.Legs())
}
// OctoCat is a Cat with a particular implementation of Legs
type OctoCat struct {
Cat
}
func (c OctoCat) Legs() int {
return 8
}
// TetraCat has a different implementation of Legs
type TetraCat struct {
Cat
}
func (c TetraCat) Legs() int {
return 4
}
func main() {
c := TetraCat{Cat{"Steve",nil}}
c.L = &c
c.PrintLegs() // want 4
o := OctoCat{Cat{"Bob",nil}}
o.L = &o
o.PrintLegs() // want 8
}
The type definitions themselves look nice and clean, but the initialization code in main is wacky (first the nil in the struct literal, then c.L = &c, what?). Is there a better solution?
A similar pattern was presented in is it possible to call overridden method from parent struct in golang?, but the question of whether this is the idiomatic way to proceed was not answered.
Two approaches I would consider for solving this:
1. Refactor your code to have a single type Cat with the fields Name string and Legs int:
package main
import (
"fmt"
)
type Cat struct {
Name string
Legs int
}
func (c *Cat) PrintLegs() {
fmt.Printf("I have %d legs.\n", c.Legs)
}
func main() {
c := &Cat{"Steve", 4}
c.PrintLegs() // want 4
o := &Cat{"Bob", 8}
o.PrintLegs() // want 8
}
https://play.golang.org/p/_PNAu3sgG8
2. Do away with the Cat type and just have TetraCat and OctoCat implement the Legger interface:
package main
import (
"fmt"
)
type Legger interface {
Legs() int
}
func PrintLegs(l Legger) {
fmt.Printf("I have %d legs.\n", l.Legs())
}
// OctoCat is a Cat with a particular implementation of Legs
type OctoCat struct {
Name string
}
func (c *OctoCat) Legs() int {
return 8
}
// TetraCat has a different implementation of Legs
type TetraCat struct {
Name string
}
func (c *TetraCat) Legs() int {
return 4
}
func main() {
c := &TetraCat{"Steve"}
PrintLegs(c) // want 4
o := &OctoCat{"Bob"}
PrintLegs(o) // want 8
}
https://play.golang.org/p/m4QvKhSj0w
Is there an elegant canonical way to implement template method pattern in Go?
In C++ this looks like this:
#include <iostream>
#include <memory>
class Runner {
public:
void Start() {
// some prepare stuff...
Run();
}
private:
virtual void Run() = 0;
};
class Logger : public Runner {
private:
virtual void Run() override {
std::cout << "Running..." << std::endl;
}
};
int main() {
std::unique_ptr<Runner> l = std::make_unique<Logger>();
l->Start();
return 0;
}
In golang i wrote something like this:
package main
import (
"fmt"
"time"
)
type Runner struct {
doRun func()
needStop bool
}
func (r *Runner) Start() {
go r.doRun()
}
func NewRunner(f func()) *Runner {
return &Runner{f, false}
}
type Logger struct {
*Runner
i int
}
func NewLogger() *Logger {
l := &Logger{}
l.doRun = l.doRunImpl
return l
}
func (l *Logger) doRunImpl() {
time.Sleep(1 * time.Second)
fmt.Println("Running")
}
func main() {
l := NewLogger()
l.Start()
fmt.Println("Hello, playground")
}
But this code fails with runtime null pointer error.
Basic idea is to mix in some functionality from derived classes (go structs) to the base class routine in a way that base class state is available from this mix-in derived routine.
The essence of the template method pattern is it allows you to inject in an implementation of a particular function or functions into the skeleton of an algorithm.
You can achieve this in Go by injecting in a function or an interface into your Runner. To achieve the basic template method pattern you don't really need your Logger struct at all:
package main
import (
"fmt"
)
type Runner struct {
run func()
}
func (r *Runner) Start() {
// some prepare stuff...
r.run()
}
func runLog() {
fmt.Println("Running")
}
func NewLogger() *Runner {
return &Runner{runLog}
}
func main() {
l := NewLogger()
l.Start()
}
Logger embeds a pointer which will be nil when you allocate the struct. That's because embedding does not put everything inside the struct, it actually creates a field (named Runner of type *Runner in your case) and the language gives you some syntactic sugar to access what's inside it. In your case it means that you can access Runner fields in two ways:
l := Logger{}
l.needStop = false
//or
l.Runner.needStop = false
To fix the error you need to allocate Runner field inside the Logger like so:
l := Logger{Runner:&Runner{}}
Or embed by value instead of pointer.
The key to have the Template Method Design Pattern work in Golang is to properly use the embedding feature and the function assignment.
Below, a code snippet which works as expected.
package main
import (
"fmt"
)
type Runner struct {
run func() // 1. this has to get assigned the actual implementation
}
func NewRunner(i func()) *Runner {
return &Runner{i}
}
func (r *Runner) Start() {
r.run()
}
type Logger struct {
Runner
}
func NewLogger() *Logger {
l := Logger{}
l.run = l.loggerRun // 2. the actual version is assigned
return &l
}
func (l *Logger) loggerRun() {
fmt.Println("Logger is running...")
}
func main() {
l := NewLogger() // 3. constructor should be used, to get the assignment working
l.Start()
}
The type Runner defines a func() attribute which is supposed to receive the actual implementation, according to the specific subtype. Start() wraps call to run(), and once invoked on the right receiver (the base one) it is be able to run the right version of run(): this happens iff in the constructor (i.e. NewLogger()) the actual version of the method run() is assigned to the attribute run of the embedded type.
And, output is:
Logger is running...
Program exited.
Here the code can be run, and modified to test any other variant of this design pattern.
I am a new to golang. I need to design a function to create object of differing types based on input. But I failed to figure out how to design the interface. Here comes my code:
package main
import (
"fmt"
)
type AA struct{
name string
}
func (this *AA) say(){
fmt.Println("==========>AA")
}
type BB struct{
*AA
age int
}
func (this *BB) say(){
fmt.Println("==========>BB")
}
func ObjectFactory(type int) *AA {
if type ==1 {
return new(AA)
}else{
return new(BB)
}
}
func main() {
obj1 := ObjectFactory(0)
obj1.say()
obj2 := ObjectFactory(0)
obj2.say()
}
The compiler tells me error no matter I ask ObjectFactory return *AA or interface{}. How can I make it work?
First off, using type as a variable name is disallowed in go (see the spec). That is your first problem.
The return type of object factory is *AA. This means that it can only return variables of type *AA, which causes the return of type of BB to fail. As defined in the spec, go doesn't have type inheritance, just struct embedding.
If you create an interface called sayer, you can use that instead of *AA in your ObjectFactory function.
type sayer interface {
say()
}
You probably want to use this interface when trying to get multiple dispatch (as demonstrated in the code below (see on play.golang.org as well).
Try this code:
package main
import (
"fmt"
)
type sayer interface {
say()
}
type AA struct{
name string
}
func (this *AA) say(){
fmt.Println("==========>AA")
}
type BB struct{
*AA
age int
}
func (this *BB) say(){
fmt.Println("==========>BB")
}
func ObjectFactory(typeNum int) sayer {
if typeNum ==1 {
return new(AA)
}else{
return new(BB)
}
}
func main() {
obj1 := ObjectFactory(1)
obj1.say()
obj2 := ObjectFactory(0)
obj2.say()
}