Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions concepts/variadic-functions/.meta/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
{
"blurb": "Variadic functions allow for an arbitrary number of arguments to be passed to a function.",
"authors": ["myworkcircle"],
"contributors": ["junedev"]
"blurb": "A variadic function accepts any number of arguments for its final parameter.",
"authors": [
"myworkcircle"
],
"contributors": [
"BNAndras",
"junedev"
]
}
107 changes: 21 additions & 86 deletions concepts/variadic-functions/about.md
Original file line number Diff line number Diff line change
@@ -1,108 +1,43 @@
# About

Usually, functions in Go accept only a fixed number of arguments.
However, it is also possible to write variadic functions in Go.

A variadic function is a function that accepts a variable number of arguments.

If the type of the last parameter in a function definition is prefixed by ellipsis `...`, then the function can accept any number of arguments for that parameter.
Typically, functions accept only a fixed number of arguments.
Prefix the last parameter's type with `...` to accept any number of trailing arguments:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Prefix the last parameter's type with `...` to accept any number of trailing arguments:
However, if you prefix the last parameter's type with `...`, the function can accept any number of trailing arguments.
This makes the last parameter a _variadic parameter_.


```go
func find(a int, b ...int) {
// ...
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
```

In the above function, parameter `b` is variadic and we can pass 0 or more arguments to `b`.

```go
find(5, 6)
find(5, 6, 7)
find(5)
```

~~~~exercism/caution
The variadic parameter must be the last parameter of the function.

If you try to write code like this ...
Inside the function, the variadic parameter is a slice:

```go
func find(...a int, b int) {}
sum(1, 2, 3) // nums is []int{1, 2, 3}
sum(1, 2, 3, 4) // nums is []int{1, 2, 3, 4}
sum() // nums is []int{}
```

... it will fail to compile with the syntax error `cannot use ... with non-final parameter b.`

Imagine the function above would work and we pass multiple arguments.
Then all those arguments will get assigned to `a` and nothing would be assigned to `b`.
Hence, variadic parameter must be provided at the end.
~~~~

The way variadic functions work is by converting the variable number of arguments to a slice of the type of the variadic parameter.

Here is an example of an implementation of a variadic function.
A function can have non-variadic parameters before the variadic one:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A function can have non-variadic parameters before the variadic one:
A function can have non-variadic parameters before the variadic one.
A function have at most one variadic parameter and it must be the last parameter.


```go
func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)

for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
return
}
func greet(greeting string, names ...string) {
for _, name := range names {
fmt.Printf("%s, %s!\n", greeting, name)
}

fmt.Println(num, "not found in ", nums)
}

func main() {
find(89, 90, 91, 95)
// Output:
// type of nums is []int
// 89 not found in [90 91 95]

find(45, 56, 67, 45, 90, 109)
// Output:
// type of nums is []int
// 45 found at index 2 in [56 67 45 90 109]

find(87)
// Output:
// type of nums is []int
// 87 not found in []
}
```

In line `find(89, 90, 91, 95)` of the program above, the variable number of arguments to the find function are `90`, `91` and `95`.
The `find` function expects a variadic int parameter after `num`.
Hence these three arguments will be converted by the compiler to a slice of type `int` `[]int{90, 91, 95}` and then it will be passed to the find function as `nums`.

Sometimes you already have a slice and want to pass that to a variadic function.
This can be achieved by passing the slice followed by `...`.
That will tell the compiler to use the slice as is inside the variadic function.
The step described above where a slice is created will simply be omitted in this case.
## Spreading a slice

```go
list := []int{1,2,3}
find(1, list...) // "find" defined as shown above
// Output:
// type of nums is []int
// 1 found at index 0 in [1 2 3]
```

It is important to note that `...` is not an actual rest and spread operator in Go.
For example, the following code does not compile.
To pass a slice into the variadic parameter, follow it with `...`:

```go
func myFunc(a int, b int, c int) {
// ...
}

func main() {
nums := []int{1, 2, 3}
myFunc(nums...)
}
nums := []int{1, 2, 3}
sum(nums...) // equivalent to sum(1, 2, 3)
```

This results in `invalid use of ... in call to myFunc` because `myFunc` does not have a variadic parameter.
`...` really only works in the specific scenarios explained above.
`...` is only valid when passing a slice to a variadic parameter.
76 changes: 21 additions & 55 deletions concepts/variadic-functions/introduction.md
Original file line number Diff line number Diff line change
@@ -1,76 +1,42 @@
# Introduction

Usually, functions in Go accept only a fixed number of arguments.
However, it is also possible to write variadic functions in Go.

A variadic function is a function that accepts a variable number of arguments.

If the type of the last parameter in a function definition is prefixed by ellipsis `...`, then the function can accept any number of arguments for that parameter.
Prefix the last parameter's type with `...` to accept any number of trailing arguments:

```go
func find(a int, b ...int) {
// ...
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
```

In the above function, parameter `b` is variadic and we can pass 0 or more arguments to `b`.
Inside the function, the variadic parameter is a slice:

```go
find(5, 6)
find(5, 6, 7)
find(5)
sum(1, 2, 3) // nums is []int{1, 2, 3}
sum(1, 2, 3, 4) // nums is []int{1, 2, 3, 4}
sum() // nums is []int{}
```

~~~~exercism/caution
The variadic parameter must be the last parameter of the function.
~~~~

The way variadic functions work is by converting the variable number of arguments to a slice of the type of the variadic parameter.

Here is an example of an implementation of a variadic function.
A function can have non-variadic parameters before the variadic one:

```go
func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)

for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
return
}
func greet(greeting string, names ...string) {
for _, name := range names {
fmt.Printf("%s, %s!\n", greeting, name)
}

fmt.Println(num, "not found in ", nums)
}

func main() {
find(89, 90, 91, 95)
// Output:
// type of nums is []int
// 89 not found in [90 91 95]

find(45, 56, 67, 45, 90, 109)
// Output:
// type of nums is []int
// 45 found at index 2 in [56 67 45 90 109]

find(87)
// Output:
// type of nums is []int
// 87 not found in []
}
```

In line `find(89, 90, 91, 95)` of the program above, the variable number of arguments to the find function are `90`, `91` and `95`.
The `find` function expects a variadic int parameter after `num`.
Hence these three arguments will be converted by the compiler to a slice of type `int` `[]int{90, 91, 95}` and then it will be passed to the find function as `nums`.
## Spreading a slice

Sometimes you already have a slice and want to pass that to a variadic function.
This can be achieved by passing the slice followed by `...`.
That will tell the compiler to use the slice as is inside the variadic function.
The step described above where a slice is created will simply be omitted in this case.
To pass a slice into the variadic parameter, follow it with `...`:

```go
list := []int{1,2,3}
find(1, list...) // "find" defined as shown above
nums := []int{1, 2, 3}
sum(nums...) // equivalent to sum(1, 2, 3)
```

`...` is only valid when passing a slice to a variadic parameter.
Loading