I have this Go code
kithttp.NewServer(
endpoints.AuthorizeUserEndpoint,
decodeRequest,
encodeResponse,
append(options, httptransport.ServerBefore(opentracing.FromHTTPRequest(tracer, "calling HTTP POST /endpoint", logger)))...,
)
Could you explain me what does append()... do with ... in the end.
The append built-in function appends elements to the end of a slice.
Read more in the docs.
The ... is used in variadic functions (of which append is an example), to pass all of the elements of the preceding variable.
So given a variable x := []int{1, 2, 3}, the expression foo(x...) will pass it to a function as if you had called foo(1, 2, 3) in contrast to foo(x) which would equivalent to foo([]int{1, 2, 3}).
Basically append takes the options slice, appends additional options to it, returns new slice and then this merged slice is passed as separate arguments to kithttp.NewServer constructor thanks to ....
Related
I am coming from javascript and know how to check if a variable exists. We can use !!var
I have come across an array in Go where I want to know if an index exists:
myArr := []int{1, 2, 3}
if myArr[3] {
fmt.Println("YES")
}
When I run this it gives me an error: Index Out Of Range: 3
Since Go is a compiled language the concept of a variable not existing does not make sense. The closest thing is that some types can take a nil value.
As far as arrays go they just have a length (without gaps). So if the length is N then only indices 0 to N-1 are valid. The built-in len() function works with any array or slice.
I want to know what exactly an asterisk does before a variable name in Kotlin.
I saw this (*args) in a Spring boot Kotlin example:
#SpringBootApplication
open class Application {
#Bean
open fun init(repository: CustomerRepository) = CommandLineRunner {
repository.save(Customer("Jack", "Bauer"))
repository.save(Customer("Chloe", "O'Brian"))
repository.save(Customer("Kim", "Bauer"))
repository.save(Customer("David", "Palmer"))
repository.save(Customer("Michelle", "Dessler"))
}
}
fun main(args: Array<String>) {
SpringApplication.run(Application::class.java, *args)
}
The * operator is known as the Spread Operator in Kotlin.
From the Kotlin Reference...
When we call a vararg-function, we can pass arguments one-by-one, e.g. asList(1, 2, 3), or, if we already have an array and want to pass its contents to the function, we use the spread operator (prefix the array with *):
It can be applied to an Array before passing it into a function that accepts varargs.
For Example...
If you have a function that accepts a varied number of arguments...
fun sumOfNumbers(vararg numbers: Int): Int {
return numbers.sum()
}
Use the spread operator to pass an array's elements as the arguments:
val numbers = intArrayOf(2, 3, 4)
val sum = sumOfNumbers(*numbers)
println(sum) // Prints '9'
Notes:
The * operator is also the multiplication operator (of course).
The operator can only be used when passing arguments to a function. The result of the operation cannot be stored since it yields no value (it is purely syntactic sugar).
The operator may confuse some C/C++ programmers at first because it looks like a pointer is being de-referenced. It isn't; Kotlin has no notion of pointers.
The operator can be used in-between other arguments when calling a vararg function. This is demonstrated in the example here.
The operator is similar to the apply function in various functional programming languages.
In addition to the answers that were directly towards "what is this thing!?!", you often have the case where you have a List and want to pass it to a function that is expecting a vararg. For this, the conversion is:
someFunc(x, y, *myList.toTypedArray())
Assuming that last parameter of someFunc is vararg of the same type as the elements in the list.
As described in the documentation this is a spread operator:
When we call a vararg-function, we can pass arguments one-by-one, e.g.
asList(1, 2, 3), or, if we already have an array and want to pass its
contents to the function, we use the spread operator (prefix the array
with *):
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
In Java you can pass an array as is but an advantage of unpacking an array with spread operator * is that spread operator lets you combine the values from an array and some fixed values in a single call. Java doesn't support this.
If a function which accept a vararg(Variable number of arguments) parameter like:
fun sum(vararg data:Int)
{
// function body here
}
Now to call this method, we can do:
sum(1,2,3,4,5)
But what if we have these value in an array, like:
val array= intArrayOf(1,2,3,4,5)
then, to call this method we have to use spread operator, like:
sum(*array)
Here, *(spread operator) will pass all content of that array.
*array is equivalent to 1,2,3,4,5
But wait a minute, what if we call it like this: sum(array)
it will give us Type Mismatch compile time error:
Type mismatch.
Required:Int
Found:IntArray
The problem is sum function accept a vararg Int parameter(which accept value like: 1,2,3,4,5) and if we pass array, it will be passed as IntArray.
What does ... mean in this context in Go?
ids = append(ids[:index], ids[index+1:]...)
I have read this great Q&A:
Do three dots (which is called wildcard?) contain multiple meanings?
about what ... means in some situations, but I don't understand what it means in the situation above.
Some languages (C, Python, ...) accept variadic arguments. Basically, you allow the client of a function to pass a number of arguments, without specifying how many. Since the function will still need to process these arguments one way or another, they are usually converted to a collection of some sort. For instance, in Python:
def foo(x, *args): # * is used for variadic arguments
return len(args)
>>> foo(1) # Passed the required argument, but no varargs
0
>>> foo(1, 2, 3) # Passed the required, plus two variadic arguments
2
>>> foo(1, 2, 3, 4, 5, 6) # required + 5 args, etc...
5
Now one obvious problem of that approach is that a number of arguments is quite a fuzzy concept as far as types are concerned. C uses pointers, Python doesn't really care about types that much in the first place, and Go takes the decision of restricting it to a specified case: you pass a slice of a given type.
This is nice because it lets the type-system do its thing, while still being quite flexible (in particular, the type in question can be an interface, so you can pass different 'actual types' as long as the function knows how to process these.
The typical example would be the Command function, which executes a program, passing it some arguments:
func Command(name string, arg ...string) *Cmd
It makes a lot of sense here, but recall that variadic arguments are just a convenient way to pass slices. You could have the exact same API with:
func Command(name string, args []string) *Cmd
The only advantage of the first is that it lets you pass no argument, one argument, several... without having to build the slice yourself.
What about your question then ?
Sometimes, you do have a slice, but need to call a variadic function. But if you do it naively:
my_args_slice := []string{"foo", "bar"}
cmd := Command("myprogram", my_args_slice)
The compiler will complain that it expects string(s), but got a slice instead ! What you want to tell it is that it doesn't have to 'build the slice in the back', because you have a slice already. You do that by using this ellipsis:
my_args_slice := []string{"foo", "bar"}
cmd := Command("myprogram", my_args_slice...) // <- Interpret that as strings
The append function, despite being built-in and special, follows the same rules. You can append zero, one, or more elements to the slice. If you want to concatenate slices (i.e. you have a 'slice of arguments' already), you similarly use the ellipsis to make it use it directly.
It unpacks slice.
ids[:index] is a short form of ids[0:index]
ids[index+1:] is a short form of ids[index+1:len(ids)-1]
So, your example ids = append(ids[:index], ids[index+1:]...) translates to
//pseudocode
ids = append(ids[0:index], ids[index+1], ids[index+2], ids[index+3], ..., ids[len(ids)-2], ids[len(ids)-1])
I'm puzzled by the following observation. On the one hand, this works:
for i in 5..10:
echo i
But as soon as I store the slice in a variable, I can no longer iterate over it, i.e., this fails:
var slice = 5..10
for i in slice:
echo i
The error is type mismatch: got (Slice[system.int]), and apparently there is no overloaded signature of the system.items iterator for Slice[T]. This raises the questions:
Why does it work at all in the first case?
Is there a workaround to iterate over a slice in the second case?
With for i in 5..10: you invoke the iterator .. (doc), which is just an alias for countup. Since this is an inline iterator it transforms the for-loop into a while-loop over the values 5 to 10. But inline iterators cannot be assigned to a variable, other than closure iterators.
With var slice = 5..10 you invoke the proc .. (doc), which generates a Slice(a: 5, b: 10). But Slices don't have a default items iterator defined.
You could iterate from slice.a to slice.b, like this:
var slice = 5..10
for i in slice.a .. slice.b:
echo i
Since this is not very nice, the proper solution is to define your own items iterator, like this:
iterator items*[T](s: Slice[T]): T =
for i in s.a .. s.b:
yield i
var slice = 5..10
for i in slice:
echo i
Since this seems pretty reasonable to me, I made a pull request to have this included in the system module: https://github.com/nim-lang/Nim/pull/2449
I'm wondering why it's not possible to do the following in go:
func main() {
stuff := []string{"baz", "bla"}
foo("bar", stuff...)
}
func foo(s ...string) {
fmt.Println(s)
}
In my understanding, slice... "explodes" the slice so it can be used for multi argument function calls. So the above example should actually expand to foo("bar", "baz", "bla").
foo(stuff...) works as expected, no surprises here, but in the example above, the compiler complains about too many arguments.
Is this a desired limitation? I'm coming from a ruby background where a foo("bar", *stuff) is perfectly fine (and is, at least in my book, the same thing), that's why this surprises me.
The value for a variadic argument can be specified either by enumerating the elements, or using an existing slice, specified by its name followed by ....
You want to mix the 2 possible ways which is not permitted by the Go Language Specification (Passing arguments to ... parameters).
If the first form is used (enumerating the elements):
The value passed [as the variadic parameter] is a new slice of type []T with a new underlying array whose successive elements are the actual arguments.
If the latter is used (passing an existing slice followed by ...) no new slice is created, the one you pass is used as is. And the passed slice can only be used to specify the value of one – the final – variadic parameter. Attempting to pass both a single element and a slice will not match the signature (the parameter list in this case) of your function and you'll get an error:
too many arguments in call to foo
There is no actual "exploding" involved in Go, the term is just used in other languages to help visualize that the passed array or slice will not be an element of the variadic parameter but will be the value of variadic parameter itself.
Mixing the 2 would require to allocate a new slice because obviously the existing slice cannot be used.
The ugly way to get this to work is make it into a new variadic.
foo(append([]string{"bar"}, stuff...)...)
And if the order doesn't matter:
foo(append(stuff, "bar")...)
https://play.golang.org/p/mY6y0vScfPB
The specification on this is at the "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 f is invoked with no actual arguments for p, the value passed to p is nil.
Otherwise, the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T.
In your case, where stuff... works:
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.
But "bar", stuff... doesn't match either case specified above.
T, []T doesn't match f([]T).
I ran into this situation when preparing arguments to feed to external commands. If possible, just build an one argument slice, then you don't have to worry about combining scalars with slices when it's time to call the function:
package main
import "os/exec"
func main() {
stuff := []string{"bar"}
stuff = append(stuff, "baz", "bla")
exec.Command("name", stuff...).Run()
}