Use one return value? - go

I want to call my function test and use one of the return values. How do I say give me the first or second value? I thought the below would give me "one" but [1] is incorrect usage causing a compile error
package main
import (
"fmt"
)
func test() (int, string) { return 1, "one"; }
func main() {
i,sz:=test()
fmt.Printf("%d=%s\n",i,sz)
fmt.Printf("%s", test()[1]) //error
}

As far as I know, you can't subscript function return values. You can do:
_, someString := test();
fmt.Println(someString);

Citing the Go Language Specification:
A primary expression of the form a[x]
denotes the element of the array, slice, string or map a indexed by x. The value x is called the index or map key, respectively. [...] Otherwise [if a is not an array, slice string or map] a[x] is illegal.
Multiple return values in Go, however, are not arrays being returned, but a separate language feature. This must be so, because an array can only hold elements of a single type, but return values can be of different types.
But since return values are not arrays (or slices, strings or maps), the a[x] syntax is, per language spec, a syntax error. As a result, as #dav has already correctly stated, you will have to actually assign the return value to a variable in order to use it elsewhere.
In special cases, you may be able to use this bit of trivia to avoid variable assignment:
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order.
Which makes the following possible:
func foo() (int, string) {
return 42, "test";
}
func bar(x int, s string) {
fmt.Println("Int: ", x);
fmt.Println("String: ", s);
}
func main() {
bar(foo())
}

Related

Reason of third return statement in method

I’m new to Go and to practice I do some coding exercice on Exercism. I stubbled on a particular exercice in which I’m having a hard time undestanding the solution. Here’s the code:
// Ints defines a collection of int values
type Ints []int
// Lists defines a collection of arrays of ints
type Lists [][]int
// Strings defines a collection of strings
type Strings []string
// Keep filters a collection of ints to only contain the members where the provided function returns true.
func (i Ints) Keep(strainer func(int) bool) (o Ints) {
for _, v := range i {
if strainer(v) {
o = append(o, v)
}
}
return
}
// Discard filters a collection to only contain the members where the provided function returns false.
func (i Ints) Discard(strainer func(int) bool) Ints {
return i.Keep(func(n int) bool { return !strainer(n) })
}
My Problem comes with the Discard Method, I dont understand the second return statement in the curly braces since the Keep function is suppose to return a value of type Ints and not a boolean statement unless I missed something, if someone could break down the Discard function for me it would be helpful.
Thanks
The Keep method takes a function as a parameter. It expects it to be func (int) bool - a function taking an int and returning a bool.
When Keep is invoked in Discard, the code passes it an anonymous function with the right signature (take int, return bool). This anonymous function invokes strainer (which is a function passed into Discard) and returns its response, negated.
The idea is that strainer is a filter function: it tells you which elements to keep. So the implementation of Keep is straightforward: iterate over all elements, and keep only those for which strainer returns true.
Discard is written in a clever way using Keep, instead of also writing a loop like this:
func (i Ints) Discard(strainer func(int) bool) (o Ints) {
for _, v := range i {
if !strainer(v) {
o = append(o, v)
}
}
return
}
It instead invokes Keep with a function that inverts the result of strainer.

How to spread arguments as parameters

I have the following Golang code:
rows, err := common.GetAll(c, req, params, timer)
return common.GenericRowMarshal(200, rows, err)
I want to figure out if it's possible to do:
return common.GenericRowMarshal(200, common.GetAll(c, req, params, timer)...)
but this doesn't compile :(
It says "not enough arguments to call..."
Anyone know if this is possible somehow?
No, each time a statement executes, the function value and parameters to the call are evaluated as usual, see doc:
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order. The call of f must contain no parameters other than the call of g, and g must have at least one return value. If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters.
func Split(s string, pos int) (string, string) {
return s[0:pos], s[pos:]
}
func Join(s, t string) string {
return s + t
}
if Join(Split(value, len(value)/2)) != value {
log.Panic("test fails")
}
If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters.
For example, the following code works:
package main
import "fmt"
func main() {
f(200, g())
}
func f(i int, slice ...interface{}) {
fmt.Println(i, slice) // 200 [[1 <nil>]]
}
func g() []interface{} {
return []interface{}{1, nil}
}
I've tried this too, thinking it might work. Currently (Go 1.13) you can only do this if the inner func returns exactly the parameters that the outer function expects.

Return only the first result of a multiple return values in golang

Absolute newbie question here.
Some functions in Go return more than one value (normally, the value and an error). I was writing a func who return the return value of one of those functions, and even if it is very easy to put the values on variables and return only the first one, I have the doubt if I could do the same in only one line without the extra variable. This is something often uses in other languages like C, Java, C#, Ruby, etc
func someFunc (param string) int {
// do something with the string, not very important
return strconv.Atoi(param)
}
I know this works
func someFunc (param string) int {
// do something with the string, not very important
var result int
result, _ = strconv.Atoi(param)
return result
}
It is this possible in Go? It is considered a "good practice" (like in Java*)
Note: Before someone say that this technique is not a good practice in Java, clarify that is not important for the question, but some people (like the ones in the company I work) encourage that style.
Use a short variable declaration for the shortest code to accomplish this goal:
func SomeFunc(parm string) int {
result, _ := strconv.Atoi(param)
return result
}
There is no one line solution without introducing a helper function that accepts two arguments and returns the first. One of these helper functions would be needed for each combination of types where you want to ignore a value.
Your best possible one-liner is a helper function written as:
func first(n int, _ error) int {
return n
}
func SomeFunc(param string) int {
return first(strconv.Atoi(param))
}
Note that:
the argument types and positions must match exactly
the second argument to first has the blank identifier (_), making it clear that you wish to completely ignore it. [1]
If you absolutely don't want to declare a named function, you may use a function literal, but that looks real ugly:
func SomeFunc(param string) int {
return func(n int, _ error) int { return n }(strconv.Atoi(param))
}
In general, the helper function is worth it if you have a lot of repetition in your code. Otherwise just use a temp variable, which looks clean and idiomatic:
func SomeFunc(param string) int {
n, _ := strconv.Atoi(param)
return n
}
Playground: https://play.golang.org/p/X8EOh_JVDDG
Once generics will be added to the language in Go 1.18, you will be able to write a helper function that can be used with any return pair and preserve type safety on the first one:
func first[T, U any](val T, _ U) T {
return val
}
func SomeFunc(param string) int {
return first(strconv.Atoi(param))
}
Go2 Playground: https://go2goplay.golang.org/p/vLmTuwzrl5o
Footnotes:
[1] Keep in mind that in case of strings.Atoi the second return value is an error, and ignoring errors is bad practice. However there are cases where the success of the operation truly doesn't matter, then it's fine to use _ to ignore the argument.

What's the difference between these two variants?

I tried to make my own code for learning how to return multiple values in main function:
package main
import "fmt"
func main() {
fmt.Println("Enter a integer:")
var I int
fmt.Scanf("%d", &I)
fmt.Println("Accepted:", I)
O := half(I)
fmt.Println("Returned:", O)
}
func half(N int) (int, bool) {
var NA int
NA = N / 2
if NA%2 == 0 {
fmt.Println("even")
return NA, true
} else {
fmt.Println("odd")
return NA, false
}
}
And given error: half.go|11| multiple-value half() in single-value context.
However another variant are working:
package main
import (
"fmt"
)
func half(number int) (int, bool) {
if x := int(number % 2); x == 0 {
return x, true
} else {
return x, false
}
}
func main() {
fmt.Println(half(1))
fmt.Println(half(2))
}
What am I doing wrong? How to overcome my error?
If a function has 2 return values, you have to "expect" both of them or none at all. More on this: Return map like 'ok' in Golang on normal functions
Your half() function has 2 return values, so when using a short variable declaration to store the returned values in variables, you have to provide 2 variables:
O, even := half(I)
fmt.Println("Returned:", O, even)
In the second case, you're not storing the returned values, you are passing them to fmt.Println() which has the signature:
func Println(a ...interface{}) (n int, err error)
fmt.Println() has a variadic parameter, so you can pass any number of arguments to it. What happens here is that all the multiple return values of half() are passed as the value of the variadic parameter of Println(). This is allowed and detailed in Spec: Calls:
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order. The call of f must contain no parameters other than the call of g, and g must have at least one return value. If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters.
Note that when doing so, you are not allowed to pass / provide extra parameters, so for example the following is also a compile-time error:
fmt.Println("Returned:", half(10))
// Error: multiple-value half() in single-value context
Check out these similar questions:
Go: multiple value in single-value context
Avoid nesting from conjunction with function that returns 2 values in go?
fmt.Println accepts any number of arguments, so is ok accepting the results of half.
In the first one, you need to provide places for both variables. Either:
i,b := half(2)
or
i, _ := half(2)
if you don't need the second return.

Is it possible to get return values selectively on single-value contexts in Go?

A simple example:
package main
import "fmt"
func hereTakeTwo() (x, y int) {
x = 0
y = 1
return
}
func gimmeOnePlease(x int){
fmt.Println(x)
}
func main() {
gimmeOnePlease(hereTakeTwo()) // fix me
}
Is it possible to pass only first returned value from hereTakeTwo() without using an explicit _ assignment? Example of what I would like to avoid:
func main() {
okJustOne, _ := hereTakeTwo()
gimmeOnePlease(okJustOne)
}
What I want is to make gimmeOnePlease function able to receive an undefined number of arguments but take only first one OR a way to call hereTakeTwo function and get only first returned value without the necessity to use _ assignments.
Or on a last resort (crazy idea) use some kind of adapter function, that takes N args and reurns only first one, and have something like:
func main() {
gimmeOnePlease(adapter(hereTakeTwo()))
}
Why? I'm just testing the boundaries of the language and learning how flexible it can be to some purposes.
No, you cannot do that apart from one special case described in the Spec:
As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order. The call of f must contain no parameters other than the call of g, and g must have at least one return value.
The best you can do besides the temporary variables (which are the best option) is this:
func first(a interface{}, _ ...interface{}) interface{} {
return a
}
func main() {
gimmeOnePlease(first(hereTakeTwo()).(int))
}
Playground: http://play.golang.org/p/VXv-tsYjXt
Variadic version: http://play.golang.org/p/ulpdp3Hppj

Resources