Is it possible to get return values selectively on single-value contexts in Go? - 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

Related

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.

How to receive multiple values returned by a method in testify framework "assert" method as an argument?

Below is a sample code , which is returning multiple values .
func (c Calc) CreateTenantHandler(item *models.TenantInput) (*models.Response, *models.ErrorDetails) {
...
...
...
return &models.Response{ResponseStatus: 201, TenantOutput: tenantoutput,}, nil
}
In test file I have tried tried doing below things.
assert.Equal(t,[nil,nil],testObject.CreateTenantHandler(nil) );
I also checked other answers but couldn't find what I need.
You don't. It has nothing to do with testify--that's just how Go works. Set multiple variables to the return values, then assert each one individually:
x, y := testObject.CreateTenantHandler(nil)
assertEqual(t, x, expectedX)
assertEqual(t, y, expectedY)
The issue is that you want to convert several return values into a single value that is usable by assert.Equal.
You can do this by passing multiple values to a variadic function that converts all the values (no matter how many) into a single slice of interfaces. That slice is then treated as a single value and works quite well with testify assert.Equal.
The shim function mentioned elsewhere is close, but it has a fixed number of parameters. makeIS() below is less code, cleaner, simpler and works with any number of return values/parameters. Put this function in your test package.
// makeIS will convert any number of parameters to a []interface{}
func makeIS(v ...interface{}) []interface{} {
return v
}
Now the assert work like this
assert.Equal(t, makeIS(eX,eY), makeIS(iReturnTwoValues())
The testify knows how to make the comparison and reports differences in the individual parameters very well. Notice this has the added benefit of "looking like" the call you want to test with the two target values to the left of the function.
One simple way to do the thing you want is to declare a function like shim:
func shim(a, b interface{}) []interface{} {
return []interface{}{a, b}
}
and then:
assert.Equal(t, shim(5,6), shim(testObject.CreateTenantHandler(nil)));
The behavior is described thoroughly in the link below:
source: http://zacg.github.io/blog/2014/10/05/go-asserts-and-multiple-return-values/
you can add convert function to fix it
package multi_return
import (
"github.com/stretchr/testify/assert"
"testing"
)
func multiReturn() (int, float32) {
return 1, 2
}
func toSlice(a ...interface{}) []interface{} {
return a
}
func TestMultiReturn(t *testing.T) {
assert.Equal(t, []interface{}{int(1), float32(2)}, toSlice(multiReturn()))
}

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.

Use one return value?

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())
}

How to access individual values from a multi-value returning function?

Go functions can return multiple values:
func f() (int, int) {
return 2, 3
}
Is there any way to access individual values from such a multi-value returning function except assignment, i.e. suppose there is
func g(i int) {...}
is there is simpler way to write the following two lines?
_, i = f()
g(i)
My personal favorite would be g(f()[1]) but that's not possible either.
The current solution used by the standard library is to write simple helper functions which are dropping the unwanted return values. For example, take a look at the template package.
A lot of functions there return a (*Template, os.Error) tuple, but there is a helper called template.Must() which only returns a *Template and panics if the error isn't nil.
Alternatively, a general helper function like func extract(index int, values ...interface{}) interface{} might do the trick. But since there isn't support for generics yet, I wouldn't write something like that.
Use an anonymous struct instead of multiple return values.
func f() (struct{i,j int}) {
return struct{i, j int}{2, 3}
}
func g(i int) { ... }
func main() {
g(f().j)
}
Of course this only works when you are writing the function. Though you can wrap existing ones with this if you want.
g(func(fst,snd int) int { return snd }(f()))
or defined snd
func snd(x, y int) int {
return y
}
g(snd(f()))
or if function return array
func f() ([2]int) {
return [2]int{2, 3}
}
g(f()[1])
There isn't a simpler way.
A possible solution would look for example like this:
g(f().1)
There is no syntactic support for a feature like this one in Go.

Resources