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.
Related
In Go, the following works (note one use of the map has one return, the other has two returns)
package main
import "fmt"
var someMap = map[string]string { "some key": "hello" }
func main() {
if value, ok := someMap["some key"]; ok {
fmt.Println(value)
}
value := someMap["some key"]
fmt.Println(value)
}
However, I have no idea how to do this same thing with my own function. Is it possible to have similar behavior with an optional return like map?
For example:
package main
import "fmt"
func Hello() (string, bool) {
return "hello", true
}
func main() {
if value, ok := Hello(); ok {
fmt.Println(value)
}
value := Hello()
fmt.Println(value)
}
Wont compile (due to the error multiple-value Hello() in single-value context) ... is there a way to make this syntax work for the function Hello()?
map is different because it is a built-in type and not a function. The 2 forms of accessing an element of a map is specified by the Go Language Specification: Index Expressions and backed by the compiler.
With functions you can't do this. If a function has 2 return values, you have to "expect" both of them or none at all.
However you are allowed to assign any of the return values to the Blank identifier:
s, b := Hello() // Storing both of the return values
s2, _ := Hello() // Storing only the first
_, b3 := Hello() // Storing only the second
You can also choose not to store any of the return values:
Hello() // Just executing it, but storing none of the return values
Note: you could also assign both of the return values to the blank identifier, although it has no use (other than validating that it has exactly 2 return values):
_, _ = Hello() // Storing none of the return values; note the = instead of :=
You can also try these on the Go Playground.
Helper function
If you use it many times and you don't want to use the blank identifier, create a helper function which discards the 2nd return value:
func Hello2() string {
s, _ := Hello()
return s
}
And now you can do:
value := Hello2()
fmt.Println(value)
Go 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic First() function which discards the second (or any further) return values:
func First[T any](first T, _ ...any) T {
return first
}
This is available in github.com/icza/gog, as gog.First() (disclosure: I'm the author).
Using it:
value := First(Hello())
fmt.Println(value)
In addition to the explanation of #icza:
I don't recommend using a helper function there. Especially if the Hello function is your own function.
However, if you can't control it, then it's fine to use a helper.
If it's your own function, it's better to change the signature of your function. Probably, you made a design mistake somewhere.
You can also do this:
package main
import "fmt"
func Hello() (string, bool) {
return "hello", true
}
func main() {
// Just move it one line above: don't use a short-if
value, ok := Hello()
if ok {
fmt.Println(value)
}
}
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 would like to understand why the code snippet below does not compile. What is the Go way of accepting a function as a function argument that may have any return type?
package main
func main() {
test(a) // Error: cannot use a (type func() string) as type func() interface {} in argument to test
test(b) // Error: cannot use b (type func() int) as type func() interface {} in argument to test
}
func a() string {
return "hello"
}
func b() int {
return 1
}
func test(x func() interface{}) {
// some code...
v := x()
// some more code....
}
Play: https://play.golang.org/p/CqbuEZGy12
My solution based on Volker's answer:
package main
import (
"fmt"
)
func main() {
// Wrap function a and b with an anonymous function
// that has an empty interface return type. With this
// anonymous function, the call signature of test
// can be satisfied without needing to modify the return
// type of function a and b.
test(func() interface{} {
return a()
})
test(func() interface{} {
return b()
})
}
func a() string {
return "hello"
}
func b() int {
return 1
}
func test(x func() interface{}) {
v := x()
fmt.Println(v)
}
Play: https://play.golang.org/p/waOGBZZwN7
You tripped over a very common misconception for Go newcomers: The empty interface interface{} does not mean "any type". Really, it does not. Go is statically typed. The empty interface interface {} is an actual (strongly typed type) like e.g. string or struct{Foo int} or interface{Explode() bool}.
That means if something has the type interface{} it has that type and not "any type".
Your function
func test(x func() interface{})
takes one parameter. This parameter is a (parameterless function) which returns a specific type, the type interface{}. You can pass any function to test which matches this signature: "No parameters and return interface{}". None of your functions a and b match this signature.
As said above: interface {} is not a magical abbreviation for "whatever",it is a distinct static type.
You have to change e.g. a to:
func a() interface{} {
return "hello"
}
Now this might look strange as you return a string which is not of type interface{}. This works because any type is assignable to variables of type interface{} (as every type has at least no methods :-).
As the Go specification states:
A function type denotes the set of all functions with the same parameter and result types
In your case, your result types differ (string vs interface{})
To be able to receive a function with any kind of result type, test would have to be defined as:
func text(x interface{}) { ... }
and then you will have to use reflect package to call the function stored in x.
Edit
Such a test function would look like this:
func test(x interface{}) {
v := reflect.ValueOf(x)
if v.Kind() != reflect.Func {
panic("Test requires a function")
}
t := v.Type()
if t.NumIn() != 0 && t.NumOut() != 1 {
panic("Function type must have no input parameters and a single return value")
}
values := v.Call(nil)
val := values[0].Interface()
// some more code..
}
Playground: https://play.golang.org/p/trC2lOSLNE
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")
}
In Go, the following works (note one use of the map has one return, the other has two returns)
package main
import "fmt"
var someMap = map[string]string { "some key": "hello" }
func main() {
if value, ok := someMap["some key"]; ok {
fmt.Println(value)
}
value := someMap["some key"]
fmt.Println(value)
}
However, I have no idea how to do this same thing with my own function. Is it possible to have similar behavior with an optional return like map?
For example:
package main
import "fmt"
func Hello() (string, bool) {
return "hello", true
}
func main() {
if value, ok := Hello(); ok {
fmt.Println(value)
}
value := Hello()
fmt.Println(value)
}
Wont compile (due to the error multiple-value Hello() in single-value context) ... is there a way to make this syntax work for the function Hello()?
map is different because it is a built-in type and not a function. The 2 forms of accessing an element of a map is specified by the Go Language Specification: Index Expressions and backed by the compiler.
With functions you can't do this. If a function has 2 return values, you have to "expect" both of them or none at all.
However you are allowed to assign any of the return values to the Blank identifier:
s, b := Hello() // Storing both of the return values
s2, _ := Hello() // Storing only the first
_, b3 := Hello() // Storing only the second
You can also choose not to store any of the return values:
Hello() // Just executing it, but storing none of the return values
Note: you could also assign both of the return values to the blank identifier, although it has no use (other than validating that it has exactly 2 return values):
_, _ = Hello() // Storing none of the return values; note the = instead of :=
You can also try these on the Go Playground.
Helper function
If you use it many times and you don't want to use the blank identifier, create a helper function which discards the 2nd return value:
func Hello2() string {
s, _ := Hello()
return s
}
And now you can do:
value := Hello2()
fmt.Println(value)
Go 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic First() function which discards the second (or any further) return values:
func First[T any](first T, _ ...any) T {
return first
}
This is available in github.com/icza/gog, as gog.First() (disclosure: I'm the author).
Using it:
value := First(Hello())
fmt.Println(value)
In addition to the explanation of #icza:
I don't recommend using a helper function there. Especially if the Hello function is your own function.
However, if you can't control it, then it's fine to use a helper.
If it's your own function, it's better to change the signature of your function. Probably, you made a design mistake somewhere.
You can also do this:
package main
import "fmt"
func Hello() (string, bool) {
return "hello", true
}
func main() {
// Just move it one line above: don't use a short-if
value, ok := Hello()
if ok {
fmt.Println(value)
}
}