I just start thinking that I begin understanding go and it quickly bytes me back :(I have a function with a signature "func AssertEqual(t *testing.T, args... interface{})" that happily works if called with strings for args... However, I have this one: "func Contains(list []interface{}, token interface{}) bool" which doesn't: if I call it with a []string and string, the compiler yells "cannot use list (type []string) as type []interface {} in function argument". I am surely missing something but I cannot grasp what. Can anyone please help sorting this out? Thank you!
[]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.""If the final argument is assignable to a slice type[]T, it may be passed unchanged as the value for a...Tparameter if the argument is followed by.... In this case no new slice is created."When you're passing individual strings the call takes those strings converts them to interface{} values and allocates a new []interface{} to put them in.When you pass a slice with '...' the call won't allocate and will instead use the slice directly. But since this is a []string and not a []interface{} it can't do that because they are different types (as mentioned in the FAQ), so you get a type error.You can do the conversion yourselfa:=[]string{"pizza","pie"}b := make([]interface,0,len(a))for _,i:= range a{b = append(b,i)}Assert(t,b...)or just just pass the strings individually,Assert(t, a[0],a[1])
Any way to "unpack" a []string slice into a scalar sequence of arguments? I guess no way, but asking just in case. Thanks!
I mean a syntax construct which does the opposite of ... and will make a call to a variadic function with a sequence of scalar arguments taken from the given slice. Example (represented by the double asterisk):func Contains(token interface{}, list... interface{}) bool {for _, v := range list {if token == v { return true }}return false}args := []string{"one", "2", "three"}ok := Contains("2", args**)
This is more than just some syntax and syntactical sugar. This wouldneed exactly the described conversion between []interface{}(which is what list in Contains basically is) and []string (which youwant to pass in). It does not matter that your ** tries to say"unpack slice": After unpacking, the resulting positional parameterswould have to be repacked to be represented by the list []interfaceslice. Nothing won.
(I know it "feels strange" at first to write the same Containsfunction twice, e.g. once for string and once for int. If you happento implement the function 25 times: Refactor massively, e.g.introduce appropriate interfaces or use reflection. If you justneed string, int and float64 why not a bit of copy&paste? Thismight be the easier/more readable/cleaner to maintain wayof doing it. Have some test to maintain correctness. Lets assumeyour Contains needs extra cases to handle NaNs or Infs in thefloat64 case: Much easier with a ContainsFloat64 version thana generic Contains. DRY is a nice principle, but it doesn't havethe status of Kant's Categorical Imperative.)