Meaning of ...interface{} (dot dot dot interface) - go

Below is a piece of Go code I have question about.
Specifically, what is a in this function?
func DPrintf(format string, a ...interface{}) (n int, err error) {
if Debug > 0 {
n, err = fmt.Printf(format, a...)
}
return
}
Could anyone tell me what the three dots are here?
And what does ...interface{} do?

A parameter type prefixed with three dots (...) is called a variadic parameter. That means you can pass any number or arguments into that parameter (just like with fmt.Printf()). The function will receive the list of arguments for the parameter as a slice of the type declared for the parameter ([]interface{} in your case). The Go Specification states:
The final parameter in a function signature may have a type prefixed with .... A function with such a parameter is called variadic and may be invoked with zero or more arguments for that parameter.
A parameter:
a ...interface{}
Is, for the function equivalent to:
a []interface{}
The difference is how you pass the arguments to such a function. It is done either by giving each element of the slice separately, or as a single slice, in which case you will have to suffix the slice-value with the three dots. The following examples will result in the same call:
fmt.Println("First", "Second", "Third")
Will do the same as:
s := []interface{}{"First", "Second", "Third"}
fmt.Println(s...)
This is explained quite well in the Go Specification as well:
Given the function and calls
func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
within Greeting, who will have the value nil in the first call, and []string{"Joe", "Anna", "Eileen"} in the second.
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
Given the slice s and call
s := []string{"James", "Jasmine"}
Greeting("goodbye:", s...)
within Greeting, who will have the same value as s with the same underlying array.

As far as the interface{} term, it is the empty interface. In other words, the interface implemented by all variables in Go.
This is sort of analogous to java.lang.Object or System.Object in C#, but is instead inclusive of every variable type in the language. So it lets you pass in anything to the method.

Related

Go - converting ...interface{} to a struct

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.

How to cleanly add an argument to a function

I have a function that's called quite a few times. How do I now add an additional parameter to that function without having to modify all the call-sites (essentially intruding the default value there and adding a bunch of noise) as well as keeping type safety?
All the languages I have previously used either support default arguments or overloading, so I am quite lost as to how I would do that.
Go doesn't have default arguments, neither it has function overloading. I think, the best you can do without changing the rest of the code is:
Rename the function Func() to FuncWithNewArg()
Add a new argument to FuncWithNewArg()
Create a new function named Func() with the original signature. Func() will call FuncWithNewArg() passing all its argument plus the default value for the new one.
The only way to add an optional argument to a function in Go is with a variadic function. As long as your function doesn't already have any variadic variables, you can add one without requiring all the existing callers to update. However, this does change the function signature, so if you have anything depending on that signature (i.e. assigning the function to a variable), such things may break.
To illustrate, suppose your function is:
func Foo(count int) error {
// do stuff
}
You could add an optional variadic variable at the end:
func Foo(count int, optional ...string) error {
// do stuff
}
You then access the optional variable as as a slice of the designated type ([]string in this case).
Now Foo() can be called as either Foo(3) or Foo(3, "bar").
Actually, it can be called with any number of arguments, so long as they match the type of the variadic variable. I.e. Foo(3, "bar", "baz", "qux") is also valid.
A function can take only a single variadic variable, and it must be the last one. This means you can't mix and match types. For example, this is invalid:
func Foo(count int, optional ...string, alsoOptional ...float64) error
If you need something more flexible than this, your best bet is to add a new function, as suggested in #bereal's answer:
func Foo(count int) error { ... }
func FooWithOther(count int, other string) error { ... }
func FooWithMany(count, int, other string, more bool) error { ... }

Unpacking slice of slices

I am curious about unpacking a slice of slices and sending them as arguments to a variadic function.
Let's say we have a function with variadic parameters:
func unpack(args ...interface{})
If we wan't to pass in a slice of interfaces it works, it doesn't matter if we unpack it or not:
slice := []interface{}{1,2,3}
unpack(slice) // works
unpack(slice...) // works
It gets tricky if we have a slice of slices. Here the compiler doesn't let us pass in an unpacked version:
sliceOfSlices := [][]interface{}{
[]interface{}{1,2},
[]interface{}{101,102},
}
unpack(sliceOfSlices) // works
unpack(sliceOfSlices...) // compiler error
The error says:
cannot use sliceOfSlices (type [][]interface {}) as type []interface {} in argument to unpack
I don't know why this happens, as we can clearly pass an []interface{} type into the function. How can I call the method unpack with the unpacked content of sliceOfSlices as arguments?
Playground example: https://play.golang.org/p/O3AYba8h4i
This is covered in Spec: Passing arguments to ... parameters:
If f is variadic with a final parameter p of type ...T, then within f the type of p is equivalent to type []T.
...
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
So in short: it is a compile-time error because sliceOfSlices (which is of type [][]interface{}) cannot be assigned to args (which is of type []interface{}) (proof on Playground).
In long:
In your first example when you do unpack(slice), since unpack() expects values of interface{}, therefore slice (which is of type []interface{}) will be wrapped in a new interface{} value, and it will be passed as a single argument.
When you do unpack(slice...), this will pass all the values of slice as separate values to unpack(); this is possible because type of slice is []interface{}, it matches the type of the variadic parameter (args ...interface{}).
In your second example when you do unpack(sliceOfSlices), again, sliceOfSlices will be wrapped in a new interface{} value and passed as a single argument.
But when you try unpack(sliceOfSlices...), that would want to pass each element of sliceOfSlices to unpack(), but type of sliceOfSlices (which is [][]interface{}) does not match the type of the variadic parameter, hence the compile-time error.
The only way to pass sliceOfSlices to unpack() "exploded" is to create a new slice whose type must be []interface{}, copy the elements, then you can pass it using ....
Example:
var sliceOfSlices2 []interface{}
for _, v := range sliceOfSlices {
sliceOfSlices2 = append(sliceOfSlices2, v)
}
unpack(sliceOfSlices2...)
Try it on the Go Playground.
Let's use the following unpack() function to verify the number of arguments:
func unpack(args ...interface{}) {
fmt.Println(len(args))
}
Running your example (and with my new slice creation), output is:
1
3
1
2
Which proves without ... only a single argument is passed (wrapped in interface{}), and using ... all elements will be passed separately.
Try this test on the Go Playground.

Golang: how to mock ...interface{} arguents using gomock

I have a Printer interface that uses the standard go Printf function signature:
type Printer interface {
Printf(format string, tokens ...interface{})
}
I would like to be able to mock this interface using gomock, but I'm not sure how setup the tokens ...interface{} argument properly.
I expected that Printf(gomock.Any(), gomock.Any()) would cover all potential cases (since tokens compiles to []interface{}), but it appears you need to setup an explicit call for N number of tokens:
// no tokens
mockPrinter.EXPECT().
Printf(gomock.Any()).
AnyTimes()
// 1 token
mockPrinter.EXPECT().
Printf(gomock.Any(), gomock.Any()).
AnyTimes()
// 2 tokens
mockPrinter.EXPECT().
Printf(gomock.Any(), gomock.Any(), gomock.Any()).
AnyTimes()
// ... up to N tokens
Does anyone know of a better way to do this?
Not possible with the current version of gomock. Maybe you can extend it, and send a pull request in. To understand why it's not possible, you have to look at the mock generated for variadic functions.
To do that, let's look at the examples in gomock's repository, specifically ./sample/mock_user/user.go and ./sample/mock_user/mock_user.go.
Generated Mock
You'll see a function in the Index inteface called Ellip, which is like your Printf function:
type Index interface {
// ...
Ellip(fmt string, args ...interface{})
// ...
}
Now, here's what the mocked function looks like for Ellip:
func (_m *MockIndex) Ellip(_param0 string, _param1 ...interface{}) {
_s := []interface{}{_param0}
for _, _x := range _param1 {
_s = append(_s, _x)
}
_m.ctrl.Call(_m, "Ellip", _s...)
}
Notice anything odd? Well, gomock is creating a slice of interfaces, _s, initialized with the first parameter. Then it appends the variadic parameters to that slice of interfaces, _s.
So, to be clear, it doesn't just append the variadic parameter, _param1, to the slice. Each individual variadic from _param1 is appended to the new slice, by iterating through it.
This means that the slice of variadic parameters is not preserved. It's broken out.
As of October 1, 2017, gomock.Any() works correctly for variadic args: https://github.com/golang/mock/pull/101

Pass string slice to variadic empty interface parameter

A package I am using, gosqlite, has a method with a variadic parameter where its type is the empty interface.
func (s *Stmt) Exec(args ...interface{}) os.Error
I can call this fine if explicitly pass individual parameters:
statement := blah()
error := statement.Exec("hello", 3.0, true) // works fine
However, as the variadic parameter corresponds to placeholders within the in operator of my SQL statement's select, the number of these placeholders is not known at compile time but dynamically changes at run time depending upon what the user is doing. E.g. I end up with SQL akin to the following if the user enters four values:
SELECT * FROM sky WHERE name IN (?,?,?,?)
So naturally I would like to call the Exec method with a slice of strings:
var values []string = getValuesFromUser()
statement := createStatementWithSufficientNumberOfPlaceholders(len(values))
_ := statement.Exec(values...) // compiler doesn't like this
This does not compile. I can get around this problem by creating an empty interface slice and copying the references over:
values2 := make([]interface{}, len(values))
for index, value := range values { values2[index] = value }
_ := statement.Exec(values2...) // compiler happy but I'm not
And this works fine but it feels a bit clunky. I was wondering if there was some trick to be able to pass values directly to this function or, failing that, a neater way of converting the string slice to an empty interface one?
Many thanks.
There is no way to pass a []string directly to a ...interface{} parameter. Doing this requires a linear time copy (with n + 1 allocations!). If the language hid this from you, it would be a significant hidden cost. Normally, passing a slice to a variadic argument just passes the slice into the function.
As for other ways of doing this, you could make it cleaner by writing a function that takes a []string and returns the corresponding []interface{}. Of course, you'll have to write it again for each []T -> []interface{} conversion you want to do, but its a rather short function, and all that changes is the signature. You could use reflection, which comes with an inherent runtime cost, to make the function "generic", such as in:
valuesVal := reflect.ValueOf(values)
...
for i := range values2 { values2[i] = valuesVal.Index(i).Interface() }
I don't have an answer. And I don't suppose there is one since even built-in and variadic copy and append have the same (or compatible concrete) element type "blockhead", but I have two obvious suggestions:
do not return []string from getValuesFromUser() (i.e. pass still unadorned []interface{}),
on the other type end wrap calls to statement.Exec() with a func making []string to []interface{} conversion.
Or on the same, third, obvious note extend type statement with Exec(args ...string).
P.S. I haven't made any benchmarks myself but I don't think this kind of conversion is highly expensive as interface{} feels like a reference type and compiler is probably doing some dirty trickstery behind the curtain... then again perhaps not, though, I'd be happy, too, to learn of an actual solution.
You need to pass a varargs slice of interface{} type like this to the method.
var paramArray []interface{}
paramArray = append(paramArray, "test1")
paramArray = append(paramArray, "test2")
varargsFunc(paramArray...)

Resources