How to return arguments to another function in Go? - go

I'm trying to create a func that accepts and returns any number of arguments. I came across anoymous functions:
func AWSApiRetry(awsFunc func()) {
return awsFunc()
}
This allows me to call a func:
AWSApiRetry(func() {
GetEnvState(sess, ApplicationName, EnvName)
})
but when I try to retrieve the return values from GetEnvState which are (string, err):
ElbReady, err := AWSApiRetry(func() {
GetEnvState(sess, ApplicationName, EnvName)
})
I'm getting the error: AWSApiRetry(func literal) used as value
How can I use my AwsApiretry func to return those types anonymously. It can be any number and type of return values, so it just sort of 'pass-through' and returns whatever the func being called returns.

You cannot.
AFAIK, in its current form, go is statically typed. What you want to do is create a function/method that returns types not known during compile time. go, by design, does not allow you to create a function/method like that

This question is roughly a year old, but no one has correctly identified the problem: the AWSApiRetry() function signature has no return. You cannot assign the return value of a function having no return value.
The actual API you're aiming to offer, defining a function with an arbitrary signature, can be accomplished using the function MakeFunc(), in the standard reflect package.
If you wanted to get more specific about the needs you observed, I'd be happy to propose a specific solution.

Does this help answer part of your question?
package main
import "fmt"
func main() {
GetEnvState := func(i ...int) {
fmt.Println(i)
}
AwsApiretry := func(awsFunc func()) {
awsFunc()
}
AwsApiretry(func() { GetEnvState(1) }) // prt [1]
AwsApiretry(func() { GetEnvState(1, 2) }) // prt [1 2]
//ElbReady := AwsApiretry(func() { GetEnvState(1, 2, 3) })
//fmt.Println(ElbReady) // AwsApiretry(func literal) used as value
}
But I also agree with #Cerise and #Kelsnare terrific answers. It is not possible to call a function/method that returns an unknown type. When ElbReady is added you get an error:
AwsApiretry(func literal) used as value

Related

Finding the type of a variable through static analysis? [duplicate]

This question already has an answer here:
Golang static identifier resolution
(1 answer)
Closed 4 months ago.
How can I determine the type of a variable through static analysis?
Suppose I have the following code:
func doSomething(x interface{}) {}
func main() {
p := Person()
doSomething(p)
}
And I want to analyze doSomething(person), is it possible to get the type of Person through static analysis?
What if there were multiple levels of assignment?
p1 := Person()
p2 := p1
doSomething(p2)
or
parent := Parent()
p := Parent.Child() // type Person
doSomething(p)
The use case is that I have a generic function that is commonly used throughout the (very large) codebase, and would like to introduce a new type safe version of this function. To do this, I hope to automatically determine the "type" of the function and refactor it accordingly:
// old
DB.InsertRow(person)
// new
Person.InsertRow(person)
Finding the type of an expression through static analysis is non-trivial, and sometimes not possible, for details see Golang static identifier resolution.
The use case is that I have a generic function that is commonly used throughout the (very large) codebase, and would like to introduce a new type safe version of this function. To do this, I hope to automatically determine the "type" of the function and refactor it accordingly:
// old
DB.InsertRow(person)
// new
Person.InsertRow(person)
Just for refactoring purposes, I don't think it is worth the hassle to implement it.
What you may do is change the signature of DB.InsertRow() temporarily to accept only a specific type such as int or your custom type you're sure is not used anywhere (e.g. type tempFoo struct{}).
To what end? Doing so, the compiler will do the hard work for you. You will see error messages showing exactly the types your codebase is trying to pass to DB.InsertRow(), so I'd say mission accomplished.
For example this code compiles:
func doSomething(x interface{}) {}
func main() {
doSomething(image.Pt(1, 2))
doSomething("abc")
doSomething(image.Rect) // image.Rect is a function which we don't call,
// so we're passing a value of a function type here
}
If we change doSomething():
func doSomething(x int) {}
We get the types we're seeking for from the compiler:
./prog.go:10:14: cannot use image.Pt(1, 2) (value of type image.Point) as type int in argument to doSomething
./prog.go:11:14: cannot use "abc" (untyped string constant) as int value in argument to doSomething
./prog.go:12:14: cannot use image.Rect (value of type func(x0 int, y0 int, x1 int, y1 int) image.Rectangle) as type int in argument to doSomething
Using the advice from Golang static identifier resolution to use golang.org/x/tools/go/types, I found that this was pretty straight forward to do with the golang.org/x/tools/go/analysis package, which has the types info available alongside the parsed ast.
This was my solution:
package rewriter
import (
"go/ast"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
func run(pass *analysis.Pass) (interface{}, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
(*ast.CallExpr)(nil),
}
inspect.Nodes(nodeFilter, func(node ast.Node, push bool) bool {
callExpr, ok := node.(*ast.CallExpr)
if !ok {
return true
}
funcExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
// check method name
if funcExpr.Sel.Name != "doSomething" {
return true
}
for _, arg := range callExpr.Args {
// lookup type of the arg
argType := pass.TypesInfo.Types[arg].Type
if argType.String() == "*rewriter.Person" {
// do whatever you want here
}
}
return false
})
return nil, nil
}
One can augment this to look at the receiver of the method and add refactoring logic as needed (using analysis.Diagnostic).

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

Passing a []fmt.Stringer parameter to a func [duplicate]

This question already has answers here:
Can I type assert a slice of interface values?
(2 answers)
Closed 3 years ago.
I have a type that implements the stringer interface
// RowID stores the ID of a single row in a table
type RowID []string
// String implements Stringer interface for RowID
func (r RowID) String() string {
return fmt.Sprintf("[%s]", strings.Join(r, ", "))
}
And I have a function that I want to pass a slice of this type (or any other type that implements the Stringer interface) to.
// PrintChanges ...
func PrintChanges(ids []fmt.Stringer) {
for _, id := range ids {
fmt.Println(id)
}
}
However, The go compiler gives me an error:
cannot use rowIDs (type []RowID) as type []fmt.Stringer in argument to PrintChanges
I can pass a RowID to a func that accepts a single fmt.Stringer
func PrintChange(id fmt.Stringer) {
fmt.Println(id)
}
...
PrintChange(RowID{"1", "24"})
But for some reason I am not able to pass a slice of RowID to a func that accepts a slice of fmt.Stringer. What am I missing?
Go Playground
Keep it simple
It is considered okay by professional Go programmers to repeat functions like this for every type, or to have a for loop over every slice you want to print. This is because Go aims to be as easy to read as possible, i.e. a person who reads a chunk of code for the first time should not be asking questions like "which function overload will this function call go to" (common pitfall in C++, Go does not have function overloads). So you can just write in main():
Playground: https://ideone.com/IL3rGR
for _, id := range rowIDs { fmt.Println(id) }
Simple and concise.
Note that fmt.Println(id) does not call your String() function
This is because the fmt library uses the reflect library and hardcodes behavior for the string type, which you are trying to replace. RowID instances are also string instances, the library always prefers string over its type aliases. I would say it is a bug in the library:
Library source: https://golang.org/src/fmt/print.go#L649
// Some types can be done without reflection.
switch f := arg.(type) {
...
case string:
p.fmtString(f, verb)
If you really want to
You can use a function that takes an interface{} and makes a runtime reflect type cast to a slice of Stringers. Note that this means you will not see type mismatches during compilation, only in runtime:
Playground: https://ideone.com/vlrBP9
func castToStringerSlice(iface interface{}) ([]fmt.Stringer, bool /* ok */) {
if reflect.TypeOf(iface).Kind() != reflect.Slice {
return nil, false
}
v := reflect.ValueOf(iface)
stringers := make([]fmt.Stringer, v.Len())
for i := 0; i < v.Len(); i++ {
stringers[i] = v.Index(i)
}
return stringers, true
}
func PrintChanges(iface_ids interface{}) {
ids, ok := castToStringerSlice(iface_ids)
if !ok {
log.Fatal(errors.New("the argument to PrintChanges must be a slice of Stringers"))
}
for _, id := range ids {
fmt.Println(id)
}
}
Resources:
Go documentation: Why does Go not support overloading of methods and operators?
Go documentation: Why does Go not have generic types?
Stack Overflow: Express function that takes any slice
Stack Overflow: Range over interface{} which stores a slice
Go documentation: Package reflect

Cannot Range Over List Type Interface {} In Function Using Go

Cannot Range Over List Type Interface {} In Function Using Go.
for me is important then i execute for in a function.
How can fix?
package main
import (
"fmt"
)
type MyBoxItem struct {
Name string
}
type MyBox struct {
Items []MyBoxItem
}
func (box *MyBox) AddItem(item MyBoxItem) []MyBoxItem {
box.Items = append(box.Items, item)
return box.Items
}
func PrintCustomArray(list interface{}) interface{} {
//items := reflect.ValueOf(list)
for _, v := range list {
fmt.Println(v.Key,v.Value)
}
return 0
}
func main() {
items := []MyBoxItem{}
item := MyBoxItem{Name: "Test Item 1"}
box := MyBox{items}
box.AddItem(item)
fmt.Println((box.Items))
PrintCustomArray(box.Items)
}
https://play.golang.org/p/ZcIBLMliq3
Error : cannot range over list (type interface {})
How can fix?
Note
The answer below describes, in broad strokes, 2 possible approaches: using interfaces, and using specific types. The approach focusing on interfaces is mentioned for completeness sake. IMHO, the case you've presented is not a viable use-case for interfaces.
Below, you'll find a link to a playground example that uses both techniques. It should be apparent to anyone that the interface approach is too cumbersome if for this specific case.
Quite apart from the fact that you don't really seem to be too familiar with how loops work in go (v.Key and v.Value are non-existent fields for example), I'll attempt to answer your question.
You are passing a list to your function, sure enough, but it's being handled as an interface{} type. That means your function accepts, essentially, any value as an argument. You can't simply iterate over them.
What you can do is use type assertions to convert the argument to a slice, then another assertion to use it as another, specific interface:
type Item interface{
key() string
val() string
}
func (i MyBoxItem) key() string {
return i.Key
}
func (i MyBoxItem) val() string {
return i.Value
}
func PrintCustomArray(list interface{}) error {
listSlice, ok := list.([]interface{})
if !ok {
return fmt.Errorf("Argument is not a slice")
}
for _, v := range listSlice {
item, ok := v.(Item)
if !ok {
return fmt.Errorf("element in slice does not implement the Item interface")
}
fmt.Println(item.key(), item.val())
}
return nil
}
But let's be honest, a function like this only works if a slice is passed as an argument. So having that first type assertion in there makes no sense whatsoever. At the very least, changing the function to something like this makes a lot more sense:
func PrintCustomArray(list []interface{})
Then, because we're not expecting an array as such, but rather a slice, the name should be changed to PrintCustomSlice.
Lastly, because we're using the same type assertion for every value in the slice, we might as well change the function even more:
// at this point, we'll always return 0, which is pointless
// just don't return anything
func PrintCustomSlice(list []Item) {
for _, v := range list {
fmt.Println(v.key(), v.val())
}
}
The advantages of a function like this is that it can still handle multiple types (all you have to do is implement the interface). You don't need any kind of expensive operations (like reflection), or type assertions.
Type assertions are very useful, but in a case like this, they merely serve to hide problems that would otherwise have resulted in a compile-time error. Go's interface{} type is a very useful thing, but you seem to be using it to get around the type system. If that's what you want to achieve, why use a typed language in the first place?
Some closing thoughts/remarks: If your function is only going to be used to iterate over specific "thing", you don't need the interfaces at all, simply specify the type you're expecting to be passed to the function in the first place. In this case that would be:
func PrintCustomSlice(list []MyBoxItem) {
for _, v := range list {
fmt.Println(v.Key, v.Value)
}
}
Another thing that I've noticed is that you seem to be exporting everything (all functions, types, and fields start with a capital letter). This, in go, is considered bad form. Only export what needs to be public. In the main package, that usually means you're hardly export anything.
Lastly, as I mentioned at the start: you don't seem to have a firm grasp on the basics just yet. I'd strongly recommend you go through the interactive tour. It covers the basics nicely, but shows you the features of the language at a decent pace. It doesn't take long, and is well worth taking a couple of hours to complete
Playground demo
It's possible to implement PrintCustomArray using the reflect package, but most experienced Go programmers will write a simple for loop:
for _, i := range box.Items {
fmt.Println("Name:", i.Name)
}
https://play.golang.org/p/RhubiCpry0
You can also encapsulate it in a function:
func PrintCustomArray(items []MyBoxItem) {
for _, i := range items {
fmt.Println("Name:", i.Name)
}
}
https://play.golang.org/p/c4EPQIx1AH
Here since you are returning box.Items from AddItem(), Items is of the type []MyBoxItem , so list should be of type []MyBoxItem .Moreover you are returning 0 in PrintCustomArray and the return type you have set is {}interface.
func PrintCustomArray(list []MyBoxItem) {
//items := reflect.ValueOf(list)
for i, v := range list {
fmt.Println(i, v)
}
//return 0
}
Again, MyBoxItem struct has only one variable named Name so v.key v.value won't make any sense.
This is what the proper code should look like https://play.golang.org/p/ILoUwEWv6Y .
You need to clear your understanding about interfaces in go. This might help https://golang.org/doc/effective_go.html#interfaces_and_types .

Optional Parameters in Go?

Can Go have optional parameters? Or can I just define two different functions with the same name and a different number of arguments?
Go does not have optional parameters nor does it support method overloading:
Method dispatch is simplified if it
doesn't need to do type matching as
well. Experience with other languages
told us that having a variety of
methods with the same name but
different signatures was occasionally
useful but that it could also be
confusing and fragile in practice.
Matching only by name and requiring
consistency in the types was a major
simplifying decision in Go's type
system.
A nice way to achieve something like optional parameters is to use variadic args. The function actually receives a slice of whatever type you specify.
func foo(params ...int) {
fmt.Println(len(params))
}
func main() {
foo()
foo(1)
foo(1,2,3)
}
You can use a struct which includes the parameters:
type Params struct {
a, b, c int
}
func doIt(p Params) int {
return p.a + p.b + p.c
}
// you can call it without specifying all parameters
doIt(Params{a: 1, c: 9})
The main advantage over an ellipsis (params ...SomeType) is that you can use the param struct with different parameter types.
For arbitrary, potentially large number of optional parameters, a nice idiom is to use Functional options.
For your type Foobar, first write only one constructor:
func NewFoobar(options ...func(*Foobar) error) (*Foobar, error){
fb := &Foobar{}
// ... (write initializations with default values)...
for _, op := range options{
err := op(fb)
if err != nil {
return nil, err
}
}
return fb, nil
}
where each option is a function which mutates the Foobar. Then provide convenient ways for your user to use or create standard options, for example :
func OptionReadonlyFlag(fb *Foobar) error {
fb.mutable = false
return nil
}
func OptionTemperature(t Celsius) func(*Foobar) error {
return func(fb *Foobar) error {
fb.temperature = t
return nil
}
}
Playground
For conciseness, you may give a name to the type of the options (Playground) :
type OptionFoobar func(*Foobar) error
If you need mandatory parameters, add them as first arguments of the constructor before the variadic options.
The main benefits of the Functional options idiom are :
your API can grow over time without breaking existing code, because the constuctor signature stays the same when new options are needed.
it enables the default use case to be its simplest: no arguments at all!
it provides fine control over the initialization of complex values.
This technique was coined by Rob Pike and also demonstrated by Dave Cheney.
Neither optional parameters nor function overloading are supported in Go. Go does support a variable number of parameters: Passing arguments to ... parameters
No -- neither. Per the Go for C++ programmers docs,
Go does not support function
overloading and does not support user
defined operators.
I can't find an equally clear statement that optional parameters are unsupported, but they are not supported either.
You can pass arbitrary named parameters with a map. You will have to assert types with "aType = map[key].(*foo.type)" if the parameters have non-uniform types.
type varArgs map[string]interface{}
func myFunc(args varArgs) {
arg1 := "default"
if val, ok := args["arg1"]; ok {
arg1 = val.(string)
}
arg2 := 123
if val, ok := args["arg2"]; ok {
arg2 = val.(int)
}
fmt.Println(arg1, arg2)
}
func Test_test() {
myFunc(varArgs{"arg1": "value", "arg2": 1234})
}
Go doesn’t support optional parameters , default values and function overloading but you can use some tricks to implement the same.
Sharing one example where you can have different number and type of arguments in one function. It’s a plain code for easy understanding you need to add error handling and some logic.
func student(StudentDetails ...interface{}) (name string, age int, area string) {
age = 10 //Here Age and area are optional params set to default values
area = "HillView Singapore"
for index, val := range StudentDetails {
switch index {
case 0: //the first mandatory param
name, _ = val.(string)
case 1: // age is optional param
age, _ = val.(int)
case 2: //area is optional param
area, _ = val.(string)
}
}
return
}
func main() {
fmt.Println(student("Aayansh"))
fmt.Println(student("Aayansh", 11))
fmt.Println(student("Aayansh", 15, "Bukit Gombak, Singapore"))
}
So I feel like I'm way late to this party but I was searching to see if there was a better way to do this than what I already do. This kinda solves what you were trying to do while also giving the concept of an optional argument.
package main
import "fmt"
type FooOpts struct {
// optional arguments
Value string
}
func NewFoo(mandatory string) {
NewFooWithOpts(mandatory, &FooOpts{})
}
func NewFooWithOpts(mandatory string, opts *FooOpts) {
if (&opts) != nil {
fmt.Println("Hello " + opts.Value)
} else {
fmt.Println("Hello")
}
}
func main() {
NewFoo("make it work please")
NewFooWithOpts("Make it work please", &FooOpts{Value: " World"})
}
Update 1:
Added a functional example to show functionality versus the sample
You can encapsulate this quite nicely in a func similar to what is below.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Println(prompt())
}
func prompt(params ...string) string {
prompt := ": "
if len(params) > 0 {
prompt = params[0]
}
reader := bufio.NewReader(os.Stdin)
fmt.Print(prompt)
text, _ := reader.ReadString('\n')
return text
}
In this example, the prompt by default has a colon and a space in front of it . . .
:
. . . however you can override that by supplying a parameter to the prompt function.
prompt("Input here -> ")
This will result in a prompt like below.
Input here ->
You could use pointers and leave them nil if you don't want to use them:
func getPosts(limit *int) {
if optParam != nil {
// fetch posts with limit
} else {
// fetch all posts
}
}
func main() {
// get Posts, limit by 2
limit := 2
getPosts(&limit)
// get all posts
getPosts(nil)
}
Go language does not support method overloading, but you can use variadic args just like optional parameters, also you can use interface{} as parameter but it is not a good choice.
I ended up using a combination of a structure of params and variadic args. This way, I didn't have to change the existing interface which was consumed by several services and my service was able to pass additional params as needed. Sample code in golang playground: https://play.golang.org/p/G668FA97Nu
I am a little late, but if you like fluent interface you might design your setters for chained calls like this:
type myType struct {
s string
a, b int
}
func New(s string, err *error) *myType {
if s == "" {
*err = errors.New(
"Mandatory argument `s` must not be empty!")
}
return &myType{s: s}
}
func (this *myType) setA (a int, err *error) *myType {
if *err == nil {
if a == 42 {
*err = errors.New("42 is not the answer!")
} else {
this.a = a
}
}
return this
}
func (this *myType) setB (b int, _ *error) *myType {
this.b = b
return this
}
And then call it like this:
func main() {
var err error = nil
instance :=
New("hello", &err).
setA(1, &err).
setB(2, &err)
if err != nil {
fmt.Println("Failed: ", err)
} else {
fmt.Println(instance)
}
}
This is similar to the Functional options idiom presented on #Ripounet answer and enjoys the same benefits but has some drawbacks:
If an error occurs it will not abort immediately, thus, it would be slightly less efficient if you expect your constructor to report errors often.
You'll have to spend a line declaring an err variable and zeroing it.
There is, however, a possible small advantage, this type of function calls should be easier for the compiler to inline but I am really not a specialist.
Another possibility would be to use a struct which with a field to indicate whether its valid. The null types from sql such as NullString are convenient. Its nice to not have to define your own type, but in case you need a custom data type you can always follow the same pattern. I think the optional-ness is clear from the function definition and there is minimal extra code or effort.
As an example:
func Foo(bar string, baz sql.NullString){
if !baz.Valid {
baz.String = "defaultValue"
}
// the rest of the implementation
}

Resources