Go supports nested struct inside function but no nested function except lambda, does it mean there is no way to define a nested class inside function?
func f() {
// nested struct Cls inside f
type Cls struct {
...
}
// try bounding foo to Cls but fail
func (c *Cls) foo() {
...
}
}
Thus it feels a bit strange that class is weaken inside function.
Any hints?
Actually it doesn't matter if you want to declare the function with or without a receiver: nesting functions in Go are not allowed.
Although you can use Function literals to achieve something like this:
func f() {
foo := func(s string) {
fmt.Println(s)
}
foo("Hello World!")
}
Here we created a variable foo which has a function type and it is declared inside another function f. Calling the "outer" function f outputs: "Hello World!" as expected.
Try it on Go Playground.
I upvoted icza's answer but just to extend it a little, here's his example slightly modified, showing that variables defined in the outer function are visible to the inner function:
func f(s string) {
foo := func() {
fmt.Println(s)
}
foo()
}
func main() {
f("Hello, World!\n")
}
Related
I have the file util.go:
func Foo(service *SomeService) error {
return helper(service)
}
func helper(service *SomeService) error {
...
}
I'm writing unit tests using testify, starting with Foo. I want to:
mock helper
assert mocked helper was called 1 time
I saw some promising solutions at https://stackoverflow.com/a/19168875/1661745, but not sure about them:
Method 1: pass helper as parameter of Foo. My doubt: testify needs a Mock struct to AssertNumberOfCalls, and here there is no struct.
Method 2: create a struct for Foo. My doubt: I don't know if it makes sense to make a struct for utils. Also requires more refactoring since callers of Foo would need a utils struct.
What's the best way to do this?
If you just want to test the args being called in helper, this is an approach that I have been using. The same test will also prove that your helper was called exactly once.
// Code
var originalFn = func(arg1, arg2 string) {
...
}
func Foo() {
originalFn(arg1,arg2)
}
// Tests
func TestFoo(t *testing.T) {
tempFn := originalFn
var fnArgs []string
originalFn = func(arg1, arg2) {
fnArgs = append(fnArgs, []string{arg1, arg2})
}
defer originalFn = tempFn
tests := []struct{
expected []string
}{
{
expected: []string{"arg1", "arg2"},
},
}
for _, tt:= range tests {
fnArgs := make([]string, 0)
Foo()
assert.Equal(t, tt.expected, fnArgs)
}
}
How to understand the last function?
Why do we use different function names after func declaration?
How to use those function? Using it like shown in the main function is wrong.
package main
import (
"fmt"
)
func main() {
fmt.Println(incrementer()) //error
}
func incrementer() func() int { //what is it?!
i := 0
return func() int {
i++
return i
}
}
It just means that the function is returning a function that takes no parameters and returns an integer. That is what the
... func() int
part of your signature is saying.
The error you are getting is because you fmt.Println cannot print a function. To show this you can see that you get the same error if you call,
func main() {
fmt.Println(foo)
}
func foo() int {
return 1
}
It might be clearer to see what is going on if you call your function like this.
func main() {
myIncrementer := incrementer()
fmt.Println(myIncrementer()) // Prints 1
}
Where you are creating incrementer, which is a function, then calling that function function which returns 1.
Simply, since incrementer() returns a function, the function that it returns must be called as well. You can do so like this:
functionFoo := incrementer()
fmt.Println(functionFoo())
Or this shorthanded way:
fmt.Println(incrementer()())
Which achieves the same thing, you just immediately execute the function that incrementer() returns.
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 :-)
}
If I have a function which takes a reference as an argument and I want to use that function to initialize a variable I need to do this inside the init() function. That solution works, but it smells not really correct to me.
Is there another way to initialize a variable for a package in go like to use the init() function?
I think that there must be a better way. I thought already about a wrapping function, but that makes the logik not better.
I prepared a short and simple example
package main
import (
"fmt"
)
var a string
//A use of a function is not allowed
//foo(&a)
//Need to call init
func init() {
foo(&a)
}
func main() {
fmt.Println(a)
}
func foo(b *string) {
*b = "abc"
}
https://play.golang.org/p/GdBiDFB1KAe
That's fine, or you can just make a pointer and assign it like this:
var a = make("abc")
func main() {
fmt.Println(*a)
}
func make(s string) *string {
return &s
}
playground
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?