How to change function reference field within method? - go

type FuncPtr func(int) int
func Foo(i int) { return i * i }
type Events struct {
SomeFunc FuncPtr
}
type Top struct {
events Events
}
func (self *Top) initEvents() {
// This change works within this function, but
// doesn't stick around after this method returns.
self.events.SomeFunc = Foo
}
func main() {
var t := Top{}
t.initEvents()
t.events.SomeFunc == nil // True: Change in initEvents() doesn't stick
}
How can I make the change inside initEvents() method persist? That is, I want to change the value of the function reference Top::Events::SomeFunc within the initEvents() method and for that change to stick once the initEvents() method returns.

The code you have works with some minor corrections to make it compileable.
There's no package declaration at the top
You're not specifying an integer return type for your function Foo
I've included a full example of the code below for convenience and if you want to run this yourself you can do it at: https://play.golang.org/p/Ngu8FFiGrI
package main
import(
"fmt"
)
type FuncPtr func(int) int
func Foo(i int) int {
return i*i
}
type Events struct {
SomeFunc FuncPtr
}
type Top struct {
events Events
}
func (self *Top) initEvents() {
// This change works within this function, but
// doesn't stick around after this method returns.
self.events.SomeFunc = Foo
}
func main() {
var t = Top{}
t.initEvents()
if t.events.SomeFunc == nil {
fmt.Println("SomeFunc not set")
}
fmt.Println("6^2 =",t.events.SomeFunc(6))
}

Related

How do you call a method on a struct with a pointer receiver using reflection?

I am working with reflection in Go and have some issues trying to call a method on a struct that has a pointer receiver. I have the following go code:
package main
import (
"fmt"
"reflect"
)
type Base struct {
Name string
Greeting string
}
func (b *Base) SetGreeting() {
b.Greeting = fmt.Sprintf("Hello %s\n", b.Name)
}
func main() {
var pointer interface{}
// create a new instance of base
mybase := Base{
Name: "reflect",
}
// create a pointer to the base
pointer = &mybase
s := reflect.ValueOf(pointer).Elem()
// get the value of s which should be a pointer
vv := reflect.ValueOf(s)
switch vv.Kind() {
case reflect.Struct:
fmt.Println("struct")
case reflect.Ptr:
fmt.Println("pointer")
}
// output struct property
fmt.Println(s.FieldByName("Name").String())
// call the method using reflect
sayHelloFunc := s.MethodByName("SetGreeting")
if sayHelloFunc.IsValid() {
sayHelloFunc.Call([]reflect.Value{})
} else {
fmt.Println("Unable to find method")
}
fmt.Println(s.FieldByName("Greeting").String())
}
The above is available at https://play.golang.org/p/V04m3LJlRia
If I change the method to use a value receiver then the method works, but I am not able to get the Greeting property. If use the pointer receiver (as in the code) the method cannot be found but I can access the property.
How can I do both?
Thanks to #Volker this is now working. The slightly modified code is:
package main
import (
"fmt"
"reflect"
)
type Base struct {
Name string
Greeting string
}
func (b *Base) SetGreeting() {
b.Greeting = fmt.Sprintf("Hello %s\n", b.Name)
}
func main() {
var pointer interface{}
// create a new instance of base
mybase := Base{
Name: "reflect",
}
// create a pointer to the base
pointer = &mybase
s := reflect.ValueOf(pointer)
// get the value of s which should be a pointer
vv := reflect.ValueOf(s)
switch vv.Kind() {
case reflect.Struct:
fmt.Println("struct")
case reflect.Ptr:
fmt.Println("pointer")
}
// output struct property
fmt.Println(s.Elem().FieldByName("Name").String())
// call the method using reflect
sayHelloFunc := s.MethodByName("SetGreeting")
if sayHelloFunc.IsValid() {
sayHelloFunc.Call([]reflect.Value{})
} else {
fmt.Println("Unable to find method")
}
fmt.Println(s.Elem().FieldByName("Greeting").String())
}
As can be seen s is no longer set as a pointer and the method can be called.
As I wanted to be able to call the properties on s I then make it a pointer using .Elem() and then I can use FieldByName.
Updated here https://play.golang.org/p/iiUrB961tUa

Golang struct composition - composed with struct cannot access its "parent"

This question appears to be a duplicate of Can embedded methods access "parent" fields?, but it is not in the sense that I know that there is no way to access the "parent" fields; I am just looking for suggestions on another way to do this, because I like the idea of the Pausable struct.
I am trying to make a convenience struct that enables other structs to receive some pausing/unpausing methods.
Imagine the following:
Pausable struct
type Pausable struct {
isPaused bool
}
func (p *Pausable) Pause() {
p.isPaused = true
}
func (p *Pausable) Unpause() {
p.isPaused = false
}
Struct that composes with Pausable
Now on my other struct I want to overwrite the Unpause() method, so that besides changing the value of p.isPaused some other stuff happens as well.
type Mystruct struct {
Pausable // Composition
}
func (s *Mystruct) Unpause() {
s.Unpause()
// Do other stuff
}
Problem
The problem becomes this. I want to add an PauseUntil() method to the Pausable struct, so that it becomes
type Pausable struct {
isPaused bool
}
func (p *Pausable) Pause() {
p.isPaused = true
}
func (p *Pausable) Unpause() {
p.isPaused = false
}
func (p *Pausable) PauseUntil(dur time.Duration) {
p.Pause()
go func() {
time.Sleep(dur)
p.Unpause()
}()
}
When the timeout runs out, however, Unpause() is called on Pausable, and not on Mystruct. What would be a clever way around this?
You could make PauseUntil a function that operates on a Pauser interface.
E.g.
type Pauser interface {
Pause()
Unpause()
}
func PauseUntil(p Pauser) {
p.Pause()
go func() {
time.Sleep(dur)
p.Unpause()
}()
}
Then you should be able to pass your myStruct to that function:
ms := new(myStruct)
PauseUntil(ms)

How to access type methods that are not defined in interface?

I have interface that requires its implementor to have Click method.
However, the type FakeTicker that implements this interface also implements Tick method in addition to Click method.
package main
type Ticker interface{
Click() string
}
type FakeTicker struct{
val string }
func (f FakeTicker) Click() string {
return f.val
}
func (f FakeTicker) Tick() int { return 1 }
func main() {
var clocker Ticker
clocker = FakeTicker{"Val"}
clocker.Tick()
}
Here I get the following error "clocker.Tick undefined (type Ticker has no field or method Tick)"
I understand that the interface only has method Click() but since FakeWriter is implementing the interface,
Shouldn't it be able to call its own method Tick()?
You would need to convert the interface{} to FakeTicker
package main
type Ticker interface {
Click() string
}
type FakeTicker struct {
val string
}
func (f FakeTicker) Click() string {
return f.val
}
func (f FakeTicker) Tick() int { return 1 }
func main() {
var clocker Ticker
clocker = FakeTicker{"Val"}
fakeTicker := clocker.(FakeTicker)
fakeTicker.Tick()
}
I understand that the interface only has method Click() but since FakeWriter is implementing the interface, Shouldn't it be able to call its own method Tick()?
Since your clocker variable is defined as the Ticker interface, you only have the methods defined on that interface. If you would like to access the Tick method, you will have to change to the FakeTicker type.
In this case, you can use type assertion.
func main() {
var clocker Ticker
clocker = FakeTicker{"Val"}
clocker.Click()
fake := clocker.(FakeTicker)
fake.Tick()
}
You should note that the type assertion will cause a panic when the assertion fails if you don't use the version with two return types (fake, ok := clocker.(FakeTicker)).

Elegant way to implement template method pattern in Golang

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.

Is it possible to bind a method at runtime?

I have the following construct:
type Foo struct {
Bar func(foo *Foo) bool
}
Because Bar is not really a method, it accepts Foo as parameter (like self in Python's bound methods). I'd however bind it to the struct as a method if there was an easy way. I suspect I could using reflection, but I want to keep it trivial. Is there a trick to bind a function to a struct? How would you do it?
Edit: I'll add a concrete example of what I'm doing.
type Route struct {
Matcher func(route *Route, r *http.Request) bool
}
Route accepts a custom Matcher function. If not set, a default matcher function is set when the route is registered:
func (mux *ServeMux) HandleRoute(r Route) {
// ...
// Set default matcher.
if r.Matcher == nil {
r.Matcher = mux.RouteMatcher
}
// ...
}
Then that function is used to do a matching:
func (mux *ServeMux) Match(r *http.Request) Route {
// ...
if route.Matcher(&route, r) {
...
}
...
}
The function is not bound to the route. My question is if this is a reasonable/idiomatic way to set a custom callable, or if there is a trick to make the function "bound" to the struct as a method.
You don't explain what you are trying to accomplish. What is wrong with this?
package main
import "fmt"
type Foo struct{}
func (f *Foo) Bar() bool {
return true
}
func main() {
var f Foo
fmt.Println(f.Bar())
}
Output:
true
Are you trying to do something like this?
package main
import "fmt"
type BarFunc func(foo *Foo) bool
type Foo struct {
BarFunc
}
func (f *Foo) Bar() bool {
return f.BarFunc(f)
}
func UserBarFunc(foo *Foo) bool { return true }
func main() {
var f Foo
f.BarFunc = UserBarFunc
fmt.Println(f.Bar())
}
Output:
true
It's not possible to bind a new method at runtime. The compiler needs to know what methods a type has at compile time. Consider this code:
package main
import "rand"
type Foo struct {}
type Bar interface {
Baz()
}
func main() {
if rand.Intn(2) != 0 {
// code to bind method Baz to Foo at runtime
}
var f Foo
// Should this compile? It depends on whether or not the if
// statement above ran, which can only be known at runtime.
f.Baz()
// Same here. The compiler can't know whether or not f has
// a method Baz.
var b Bar = f
}
Your example code looks like a reasonable way to do what you want. PeterSO's answer presents another way to do it that makes the function look more like a regular method.
How about you create a helper method with the desired name (Bar) that chooses and calls the desired function at runtime?

Resources