Turning []interface{} into arguments to a non-variadic function - go

I am looking for an elegant way to unzip a list of arguments in Go. I do not want to use a variadic function for that purpose because in my usecase when writing a function I already know the number of arguments and I want to keep that part simple. However in my usecase the parameters arrive as []interface{}.
I could not find a solution but hey maybe someone out there already knows how to do that?
package main
import (
"fmt"
)
// NON-VARIADIC greater
func greet(n1, n2 string) {
fmt.Printf("%s %s\n", n1, n2)
}
func main() {
l := []interface{}{"hello", "world"}
// works
greet(l[0].(string), l[1].(string))
// does not work: "./args.go:20: not enough arguments in call to greet"
//greet(l...)
// is there something more elegant to unzip the list?
}

You could create a "generic" caller using reflect package, although this comes with overhead and lacks type safety. Unless you have some special case situation and don't know what you want to call in the code, it would be wiser to use the snippet from your question which works, but you consider not elegant.
Example usage of reflect which could be your starting point:
package main
import (
"fmt"
"reflect"
)
func call(f interface{}, args []interface{}) {
// Convert arguments to reflect.Value
vs := make([]reflect.Value, len(args))
for n := range args {
vs[n] = reflect.ValueOf(args[n])
}
// Call it. Note it panics if f is not callable or arguments don't match
reflect.ValueOf(f).Call(vs)
}
func greet(n1, n2 string) {
fmt.Printf("%s %s\n", n1, n2)
}
func main() {
l := []interface{}{"hello", "world"}
call(greet, l)
}
// Output: hello world
https://play.golang.org/p/vbi3CChCdV

I'm not quite sure what you're trying to do. If you want a way to easily pass a slice of two empty interfaces to a function that accepts two strings, you can create a little helper:
func twoStrings(vs []interface{}) (string, string) {
return vs[0].(string), vs[1].(string)
}
Use it as
greet(twoStrings(l))
Playground: http://play.golang.org/p/R8KFwMUT_V.
But honestly, it seems like you're doing something wrong, trying to make the Go type system to do something it cannot do.

Related

Deep equal on function value

From reflect package, I use DeepEqual function check similarity of both value. It works until I use function as value.
package main
import "fmt"
import "reflect"
type thisHandler func(s string)
func main() {
var a thisHandler = func(s string) {
fmt.Println(s)
}
b := a
c := a
fmt.Println(b)
fmt.Println(c)
fmt.Println(reflect.DeepEqual(b,c))
}
Playground
Why can't DeepEqual check similarity of value of a function?
Based on it's documentation said:
https://golang.org/pkg/reflect/#DeepEqual
...
Func values are deeply equal if both are nil; otherwise they are
not deeply equal.
...
In general DeepEqual is a recursive relaxation
of Go's == operator. However, this idea is impossible to implement
without some inconsistency. Specifically, it is possible for a value
to be unequal to itself, either because it is of func type
(uncomparable in general)...

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

How to write a pop() function

a := []int{1,2,3}
x, a := a[len(a)-1], a[:len(a)-1]
fmt.Println(a,x)
How to create a pop() function that will do the same for any type of an array?
Here is what I came up with so far:
func pop(a []*interface{}) interface{}{
x := a[len(a)-1]
a = a[:len(a)-1]
return x
}
func main(){
a := []int{1,2,3}
x = pop(a)
fmt.Println(a,x) // -> [1,2] 3
}
But I get cannot use a (type []int) as type []interface {}or other error messages if I try to tweak the code by trial and error.
package main
import (
"fmt"
"reflect"
)
func pop(a interface{}) interface{} {
v := reflect.ValueOf(a).Elem()
x := v.Index(v.Len() - 1)
v.SetLen(v.Len() - 1)
return x
}
func main() {
a := []int{1, 2, 3}
x := pop(&a)
fmt.Println(a, x) // -> [1,2] 3
}
Though this can be implemented, I still think that x, a = a[len(a)-1], a[:len(a)-1] should be better than a pop function.
The go type system doesn't allow you to cast from []type1 -> []type2. Even if it did interfaces are a struct containing a type id and pointer to the object, where normally you would just have the object. Because of this you need to take a interface{} and use reflect to do the slicing.
func pop(slice interface{}) (interface{}, interface{}) {
v := reflect.ValueOf(slice)
return v.Slice(0,v.Len()-1).Interface(), v.Index(v.Len()-1).Interface()
}
Go Playground
Note that this loses compile time type safety, because it must use an interface. Additionally, due to using interfaces the poped value may be allocated, creating extra GC pressure.
Common Go style typically recommends not writing a function like this, and just inlining the small amount of code manually.
After all that really good anwers using reflection I also want to add one answer which offers a more idiomatic Go solution. Like Rob Pike said in his great talk about Go Proverbs
interface{} says nothing
Reflection is never clear
So there should be also one answer showing the idiomatic Go way. This solution does not work for slices of standard types. But there the answer of cshu shows the best solution: x, a = a[len(a)-1], a[:len(a)-1]
For own defined types we have to define a Poper interface and the Pop function takes that as input and returns an empty interface.
type Poper interface {
Pop() interface{}
}
type MyType struct {
a []int
}
func (mt *MyType) Pop() interface{} {
x := mt.a[len(mt.a)-1]
mt.a = mt.a[:len(mt.a)-1]
return x
}
func Pop(p Poper) interface{} {
return p.Pop()
}
func main() {
a := &MyType{[]int{1, 2, 3}}
fmt.Println(Pop(a), a)
}
https://play.golang.org/p/UbDkoVYSMA
At all it is not a good idea to return an empty interface, because all following code has to support the interface{}.
The following code example does not work:
func main() {
a := &MyType{[]int{1, 2, 3}}
fmt.Println(Pop(a), a)
var b int
b = Pop(a)
}
https://play.golang.org/p/wg9__O44A8
The error says everything about that problem: cannot use Pop(a) (type interface {}) as type int in assignment: need type assertion
So the Pop() function does work by returning interface{} but the rest of the code using the result of that function needs to make a type assertion. So if you can avoid it you should search for another solution using types.

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

Use Array as function call arguments

In JavaScript, you can use .apply to call a function and pass in an array/slice to use as function arguments.
function SomeFunc(one, two, three) {}
SomeFunc.apply(this, [1,2,3])
I'm wondering if there's an equivalent in Go?
func SomeFunc(one, two, three int) {}
SomeFunc.apply([]int{1, 2, 3})
The Go example is just to give you an idea.
They are called variadic functions and use the ... syntax, see Passing arguments to ... parameters in the language specification.
An example of it:
package main
import "fmt"
func sum(nums ...int) (total int) {
for _, n := range nums { // don't care about the index
total += n
}
return
}
func main() {
many := []int{1,2,3,4,5,6,7}
fmt.Printf("Sum: %v\n", sum(1, 2, 3)) // passing multiple arguments
fmt.Printf("Sum: %v\n", sum(many...)) // arguments wrapped in a slice
}
Playground example
It is possible using reflection, specifically Value.Call, however you really should rethink why you want to do that, also look into interfaces.
fn := reflect.ValueOf(SomeFunc)
fn.Call([]reflect.Value{reflect.ValueOf(10), reflect.ValueOf(20), reflect.ValueOf(30)})
playground

Resources