How can I pass in Golang a function as an argument that can have potentially multiple arguments, e.g. fmt.Printf?
The first problem is that one has to define the type of the function to be passed first.
type FunctionWithVariableArgumentLength func(s string, object1 type1, ..., objectn typen)
The second problem is that one does not know what types the arguments in the list may have, like in fmt.Printf.
There's a prototype as for other functions : http://golang.org/pkg/fmt/#Printf
So you can define your function accepting a function as argument like this :
func exe(f func(string, ...interface{}) (int, error)) {
f("test %d", 23)
}
func main() {
exe(fmt.Printf)
}
Demonstration
You would use a similar signature as the one for fmt.Printf
func yourFunction(a ...interface{})
To answer the 1st part: writing functions with a variable number of arguments.
// sums returns the total of a variable number of arguments
func sum(numbers ...int) total int {
total = 0
for _, n := range numbers {
total += n
}
return total
}
The 2nd Part is harder but the function definition looks like:
func doVarArgs(fmt string, a ...interface{}) {
The variable a contains a slice of values of the type interface{}. You then iterate over the slice pulling each argument and using the package "reflect" to query the type of each argument.
See http://golang.org/pkg/reflect/ for a full explanation.
Related
I have a scenario where I'm calling a function leveraging a common background worker thread that has arguments as func somefunction(data ...interface{}) to be generic and reusable across the application.
In one of the functions, the number of arguments are more and in the unction definition, I am casting the array items individually like
someVar := data[0].(string)
Now this approach is fine when I'm usually dealing with 1-2 arguments. But it becomes tedious when the number of arguments increases.
So is there a cleaner way to parse the elements into a struct in the order of their appearance?
My objective is to do this in a cleaner way rather than individually getting one from array and casting to a string variable.
Sample code explaining the scenario https://go.dev/play/p/OScAjyyLW0W
Use the reflect package to set fields on a value from a slice of interface{}. The fields must be exported.
// setFields set the fields in the struct pointed to by dest
// to args. The fields must be exported.
func setFields(dest interface{}, args ...interface{}) {
v := reflect.ValueOf(dest).Elem()
for i, arg := range args {
v.Field(i).Set(reflect.ValueOf(arg))
}
}
Call it like this:
type PersonInfo struct {
ID string // <-- note exported field names.
Name string
Location string
}
var pi PersonInfo
setFields(&pi, "A001", "John Doe", "Tomorrowland")
Playground Example.
I'm trying to expand my knowledge of Go's function pointers, and I have a question about what is and is not possible with passing functions as parameters in Go.
Let's say that I want to write a decorator() function that can wrap any existing function. For simplicity, let's limit this to functions that accept exactly one parameter and return exactly one value.
If I write a decorator that accepts func(interface{}) interface{} as it's argument, it will implicitly work as long as that function I pass in also accepts/returns an interface{} type (see funcA).
My question is--is there a way to convert an existing function of type func(string) string to a type of func(interface{}) interface{} so that it can also be passed into a decorator function without just wrapping it in a new anonymous function (see funcB)?
package main
import (
"fmt"
)
func decorate(inner func(interface{}) interface{}, args interface{}) interface {} {
fmt.Println("Before inner")
result := inner(args)
fmt.Println("After inner")
return result
}
func funcA(arg interface{}) interface{} {
fmt.Print("Inside A, with arg: ")
fmt.Println(arg)
return "This is A's return value"
}
func funcB(arg string) string {
fmt.Print("Inside B, with arg: ")
fmt.Println(arg)
return "This is B's return value"
}
func main() {
// This one works. Output is:
//
// Before inner
// Inside A, with arg: (This is A's argument)
// After inner
// This is A's return value
//
fmt.Println(decorate(funcA, "(This is A's argument)"))
// This doesn't work. But can it?
//fmt.Println(decorate(funcB, "(This is B's argument)"))
}
This is not possible. One reason for that is the mechanics of passing parameters differ from function to function, and using an interface{} arg does not mean "accept anything". For example, a function taking a struct as an arg will receive each member of that struct, but a function taking an interface{} containing that struct will receive two words, one containing the type of the struct, and the other containing a pointer to it.
So, without using generics, the only way to implement this is by using an adapter function.
Use the reflect package to handle functions with arbitrary argument and result types.
func decorate(inner interface{}, args interface{}) interface{} {
fmt.Println("Before inner")
result := reflect.ValueOf(inner).Call([]reflect.Value{reflect.ValueOf(args)})
fmt.Println("After inner")
return result[0].Interface()
}
Run the code on the playground.
Like the decorate function in the question, the function in this answer assumes one argument and one result. The function must be modified to handle other function types.
The OP should consider the tradeoffs between the anonymous wrapper function proposed in the question and the use of the reflect package here. Calling the function through the reflect API is slower than calling the function through the anonymous wrapper. There's also a loss of type safety with the reflect API. The anonymous wrapper function adds verbosity.
For the record, with Go 1.18 and the introduction of generics, the decorator function becomes almost trivial.
You may declare a type constraint as such:
type UnaryFunc[T any] interface {
func(T) T
}
The constraint itself is parametrized with T to allow for unary functions that take and return arbitrary types.
In the decorate function you then instantiate the constraint with a type parameter. The signature becomes:
decorate[T any, F UnaryFunc[T]](inner F, arg T) T
Thanks to type inference, you can just pass concrete arguments to the function, and both T and F will be unambiguous.
Example alternatives without a named constraint:
// accept and return T
decorate[T any](inner func(T) T, arg T) T
// only return T
decorate[T any](inner func() T) T
// return T and error
decorate[T any](inner func(T) (T, error), arg T) (T, error)
// N-ary function
decorate[T, U any](inner func(T, U) (T, error), argt T, argu U) (T, error)
The obvious limitation is that the interface constraint UnaryFunc specifies only functions that take and return exactly one arg of type T. You can't do otherwise, because the type set of an interface constraint may include types which support the same operations — and calling with one arg is not compatible with calling with N args.
The full program:
package main
import (
"fmt"
)
type UnaryFunc[T any] interface {
func(T) T
}
func decorate[T any, F UnaryFunc[T]](inner F, arg T) T {
fmt.Println("before inner")
result := inner(arg)
fmt.Println("after inner")
return result
}
func funcA(arg int) int {
fmt.Println("inside A with:", arg)
return arg
}
func funcB(arg string) string {
fmt.Println("inside B with:", arg)
return arg
}
func main() {
// this works
decorate(funcA, 200)
// this also works
decorate(funcB, "Func B")
}
Playground: https://go.dev/play/p/3q01NiiWsve
is there a way to convert an existing function of type func(string) string to a type of func(interface{}) interface{} so that it can also be passed into a decorator function without just wrapping it in a new anonymous function (see funcB)?
No. It's that simple: No.
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.
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
I was going through some code written in Google's Go language, and I came across this:
func Statusln(a ...interface{})
func Statusf(format string, a ...interface{})
I don't understand what the ... means. Does anybody know?
It means that you can call Statusln with a variable number of arguments. For example, calling this function with:
Statusln("hello", "world", 42)
Will assign the parameter a the following value:
a := []interface{}{"hello", "world", 42}
So, you can iterate over this slice a and process all parameters, no matter how many there are. A good and popular use-case for variadic arguments is for example fmt.Printf() which takes a format string and a variable number of arguments which will be formatted according to the format string.
It is variable length argument
func Printf(format string, v ...interface{}) (n int, err error) {
Take for example this signature. Here we define that we have one string to print, but this string can be interpolated with variable number of things (of arbitrary type) to substitude (actually, I took this function from fmt package):
fmt.Printf("just i: %v", i)
fmt.Printf("i: %v and j: %v",i,j)
As you can see here, with variadic arguments, one signature fits all lengths.
Moreover, you can specify some exact type like ...int.
They are variadic functions. These functions accept a variable number of arguments.
Example
The sums function below accepts multiple integers:
package main
import "fmt"
func sum(nums ...int) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func main() {
sum(1, 2)
sum(1, 2, 3)
nums := []int{1, 2, 3, 4}
sum(nums...)
}
For more info
Go By Example: Variadic Functions
Wikipedia: Variadic Functions