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?
Related
This question already has answers here:
How to mock a method call of a struct in test case at go
(2 answers)
Closed 4 years ago.
So I am a beginner with mocking struct and functions in Golang. I basically want to check if a function has been called for unit testing purpose. Here is the code:
type A struct {
}
func (a *A) Foo (){}
type B struct {
a *A
}
func (b* B) Bar () {
a.Foo()
}
I basically want to check that Foo is indeed called when Bar is called
I know there is some mock framework available for Golang but they are pretty complicated when it comes to testing existing struct and struct methods
If you want to test B and see if it really calls A's Foo function, you need to mock out the A object. Since the function you want to check for is Foo, just create a simple Fooer interface (which is what you would call it in Go, the function plus 'er') with only that function. Replace B's reference to A with one to Fooer and you are good. I created a little sample based on your code here on the Go Playground:
package main
import "testing"
type A struct {
}
func (a *A) Foo() {}
type Fooer interface {
Foo()
}
type B struct {
a Fooer
}
func (b *B) Bar() {
b.a.Foo()
}
func main() {
var a A
var b B
b.a = &a
b.Bar()
}
// in your test:
type mockFooer struct {
fooCalls int
}
func (f *mockFooer) Foo() {
f.fooCalls++
}
func Test(t *testing.T) {
var mock mockFooer
var bUnderTest B
bUnderTest.a = &mock
bUnderTest.Bar()
if mock.fooCalls != 1 {
t.Error("Foo not called")
}
}
Edit: I'm not asking how to initialize variables correctly. I'm asking how to prevent them from being initialized incorrectly, so that functions that take that type don't have to explicitly validate their arguments.
In Go, I have a type that contains maps, e.g.:
package foo
type Bar struct {
baz map[string]int
total int
}
func NewBar() *Bar {
return &Bar{baz: map[string]int{}}
}
func (b *Bar) IncrementBaz(key string) {
f.baz[key] = f.baz[key] + 1
f.total++
}
// ...
If another package initializes the type and then tries to write to it, it will try to write to a nil map, causing a segfault:
package main
import "foo"
func main() {
var b foo.Bar
b.IncrementBaz("some_key") // write to nil map -> segfault
// ...
}
To prevent this, I want to make it so that other packages can't initialize an empty foo.Bar.
I can't simply make it unexported, because I want functions in other packages to be able to declare it as an argument or return type. If I wrap it in an interface, I get a similar problem:
package "foo"
type Bar interface {
IncrementBaz(string)
// ...
}
type bar struct {
baz map[string]int
total int
}
func NewBar() Bar {
return &bar{baz: map[string]int{}}
}
func (b *bar) IncrementBaz(key string) {
f.baz[key] = f.baz[key] + 1
f.total++
}
// ...
Similar problem:
package main
import "foo"
func main() {
var b foo.Bar
b.IncrementBaz("some_key") // method call on nil interface -> segfault
// ...
}
Is there any way to have an exported type that only the package that declares it can initialize it?
Now foo.Bar is just an interface type. The default value is a nil pointer. You are very close, just initialize it as b := foo.NewBar()
Rule is, methods can be defined only on named type and pointer to named type.
For the below code,
package main
type Cat struct {
}
func (c Cat) foo() {
// do stuff_
}
func (c *Cat) foo() {
// do stuff_
}
func main() {
}
compiler gives error:
main.go:10: method redeclared: Cat.foo
method(Cat) func()
method(*Cat) func()
Above code defines,
method foo() for named type(Cat) and
method foo() for pointer to named type(*Cat).
Question:
For GO compiler, Why methods defined for different type is considered
same?
In Go, receivers are a kind of syntactic sugar. The actual, runtime signature of function (c Cat) foo() is foo(c Cat). The receiver is moved to a first parameer.
Go does not support name overloading. There can be only one function of with name foo in a package.
Having said the statements above, you see that there would be two functions named foo with different signatures. This language does not support it.
You cannot do that in Go. The rule of thumb is to write a method for a pointer receiver and Go will use it whenever you have a pointer or value.
If you still need two variants, you need name the methods differently.
For example, you can model some feline behavior like this:
package main
import (
"fmt"
)
type Growler interface{
Growl() bool
}
type Cat struct{
Name string
Age int
}
// *Cat is good for both objects and "object references" (pointers to objects)
func (c *Cat) Speak() bool{
fmt.Println("Meow!")
return true
}
func (c *Cat) Growl() bool{
fmt.Println("Grrr!")
return true
}
func main() {
var felix Cat // is not a pointer
felix.Speak() // works :-)
felix.Growl() // works :-)
var ginger *Cat = new(Cat)
ginger.Speak() // works :-)
ginger.Growl() // works :-)
}
when I run the code snippet bellow, it raise a error
a.test undefined (type interface {} is interface with no methods)
It seem the type switch does not take effect.
package main
import (
"fmt"
)
type A struct {
a int
}
func(this *A) test(){
fmt.Println(this)
}
type B struct {
A
}
func main() {
var foo interface{}
foo = A{}
switch a := foo.(type){
case B, A:
a.test()
}
}
If I change it to
switch a := foo.(type){
case A:
a.test()
}
it's ok now.
This is normal behaviour that is defined by the spec (emphasis mine):
The TypeSwitchGuard may include a short variable declaration. When that form is used, the variable is declared at the beginning of the implicit block in each clause. In clauses with a case listing exactly one type, the variable has that type; otherwise, the variable has the type of the expression in the TypeSwitchGuard.
So, in fact, the type switch does take effect, but the variable a keeps the type interface{}.
One way you could get around this is to assert that foo has the method test(), which would look something like this:
package main
import (
"fmt"
)
type A struct {
a int
}
func (this *A) test() {
fmt.Println(this)
}
type B struct {
A
}
type tester interface {
test()
}
func main() {
var foo interface{}
foo = &B{}
if a, ok := foo.(tester); ok {
fmt.Println("foo has test() method")
a.test()
}
}
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))
}