Skip to content

Commit 067115b

Browse files
committed
add variadic functions examples
1 parent d5a6b37 commit 067115b

File tree

23 files changed

+445
-1
lines changed

23 files changed

+445
-1
lines changed

.DS_Store

10 KB
Binary file not shown.

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.idea/

0-basic-variadic-example/main.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func main() {
6+
say1("1", "2", "3", "\n")
7+
say1(append([]string{"1", "2", "3"}, append([]string{}, "4", "5", "6", "\n")...)...)
8+
9+
say2("1", "2", "3", "\n")
10+
args := []interface{}{"4", "5", "6"}
11+
say2(args...)
12+
}
13+
14+
func say1(args ...string) {
15+
for _, a := range args {
16+
fmt.Print(a)
17+
}
18+
}
19+
20+
// individual arguments can be of any type
21+
// destructured slice arguments have to be of type interface{}
22+
func say2(args ...interface{}) {
23+
fmt.Print(args...)
24+
}

1-cmd-no-variadic/.DS_Store

6 KB
Binary file not shown.

1-cmd-no-variadic/main.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package main
2+
3+
var commands = map[string]Command{}
4+
5+
func main() {
6+
// create new command
7+
command := cmd("get", "get todo by id", []string{"id"})
8+
command.Execute()
9+
10+
// get the existing command
11+
command = cmd("get", "", nil)
12+
command.Execute()
13+
}
14+
15+
func cmd(name, description string, args []string) Command {
16+
c, ok := commands[name]
17+
if ok {
18+
return c
19+
}
20+
c = Command{
21+
Name: name,
22+
Description: description,
23+
Args: args,
24+
}
25+
commands[name] = c
26+
return c
27+
}
28+
29+
type Command struct {
30+
Name string
31+
Description string
32+
Args []string
33+
}
34+
35+
func (c Command) Execute() {
36+
}

2-cmd-setter-getter/.DS_Store

6 KB
Binary file not shown.

2-cmd-setter-getter/main.go

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package main
2+
3+
var commands = map[string]Command{}
4+
5+
func main() {
6+
// create new command
7+
command := createCmd("get", "get todo by id", []string{"id"})
8+
command.Execute()
9+
10+
// get the existing command
11+
command = getCmd("get")
12+
command.Execute()
13+
}
14+
15+
func createCmd(name, description string, args []string) Command {
16+
c := Command{
17+
Name: name,
18+
Description: description,
19+
Args: args,
20+
}
21+
commands[name] = c
22+
return c
23+
}
24+
25+
func getCmd(name string) Command {
26+
c, ok := commands[name]
27+
if ok {
28+
return c
29+
}
30+
return Command{}
31+
}
32+
33+
type Command struct {
34+
Name string
35+
Description string
36+
Args []string
37+
}
38+
39+
func (c Command) Execute() {
40+
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package main
2+
3+
var commands = map[string]Command{}
4+
5+
func main() {
6+
// create new command
7+
command := cmd(Args{
8+
Name: "get",
9+
Description: "get todo by id",
10+
Args: []string{"id"},
11+
})
12+
command.Execute()
13+
14+
// get the existing command
15+
command = cmd(Args{Name: "get"})
16+
command.Execute()
17+
}
18+
19+
type Args struct {
20+
Name string
21+
Description string
22+
Args []string
23+
}
24+
25+
func cmd(args Args) Command {
26+
c, ok := commands[args.Name]
27+
if ok {
28+
return c
29+
}
30+
31+
c = Command{
32+
Name: args.Name,
33+
Description: args.Description,
34+
Args: args.Args,
35+
}
36+
commands[args.Name] = c
37+
return c
38+
}
39+
40+
type Command struct {
41+
Name string
42+
Description string
43+
Args []string
44+
}
45+
46+
func (c Command) Execute() {
47+
}

4-cmd-variadic-all-optional/.DS_Store

6 KB
Binary file not shown.

4-cmd-variadic-all-optional/main.go

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package main
2+
3+
var commands = map[string]Command{}
4+
5+
func main() {
6+
// create new command
7+
command := cmd("get", "get todo by id", "id")
8+
command.Execute()
9+
10+
// get the existing command
11+
command = cmd("get")
12+
command.Execute()
13+
}
14+
15+
func cmd(args ...string) Command {
16+
name, description, arguments := "", "", make([]string, 0)
17+
if len(args) > 0 {
18+
name = args[0]
19+
}
20+
c, ok := commands[name]
21+
if ok {
22+
return c
23+
}
24+
25+
if len(args) > 1 {
26+
description = args[1]
27+
}
28+
if len(args) > 2 {
29+
arguments = args[2:]
30+
}
31+
c = Command{
32+
Name: name,
33+
Description: description,
34+
Args: arguments,
35+
}
36+
commands[name] = c
37+
return c
38+
}
39+
40+
type Command struct {
41+
Name string
42+
Description string
43+
Args []string
44+
}
45+
46+
func (c Command) Execute() {
47+
}
6 KB
Binary file not shown.

5-cmd-variadic-mandatory-args/main.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package main
2+
3+
var commands = map[string]Command{}
4+
5+
func main() {
6+
// create new command
7+
command := cmd("get", "get todo by id", "id")
8+
command.Execute()
9+
10+
// get the existing command
11+
command = cmd("get")
12+
command.Execute()
13+
}
14+
15+
func cmd(name string, args ...string) Command {
16+
description, arguments := "", make([]string, 0)
17+
c, ok := commands[name]
18+
if ok {
19+
return c
20+
}
21+
22+
if len(args) > 1 {
23+
description = args[1]
24+
}
25+
if len(args) > 2 {
26+
arguments = args[2:]
27+
}
28+
c = Command{
29+
Name: name,
30+
Description: description,
31+
Args: arguments,
32+
}
33+
commands[name] = c
34+
return c
35+
}
36+
37+
type Command struct {
38+
Name string
39+
Description string
40+
Args []string
41+
}
42+
43+
func (c Command) Execute() {
44+
}

README.md

+41-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,42 @@
1-
# variadic-functions
1+
# Variadic function in Go (Practical use cases)
2+
23
Variadic functions in Go (practical use cases)
4+
5+
### Motivation
6+
7+
- Accept an arbitrary number of arguments
8+
- Simulate optional arguments
9+
10+
### Examples
11+
12+
Here are some examples of variadic function in the Go standard library
13+
14+
### Rules
15+
16+
- variadic argument has to be the last one
17+
18+
### Pros
19+
20+
- Clean and elegant API
21+
22+
### Cons
23+
24+
- Generic and ambiguous arguments and argument names
25+
- No automatic conversion for `[]interface{}` aka `[]any`
26+
27+
### Caveats
28+
29+
Returning the passed slice
30+
You can’t use a variadic param as a result type, but, you can return it as a slice.
31+
32+
func f(nums ...int) []int {
33+
nums[1] = 10
34+
return nums
35+
}
36+
37+
### Resources
38+
39+
- [Appending and copying slices - Go Spec](https://go.dev/ref/spec#Appending_and_copying_slices)
40+
- [Passing arguments to variadic functions - Go Spec](https://go.dev/ref/spec#Passing_arguments_to_..._parameters)
41+
- [Types Assignability - Go Spec](https://go.dev/ref/spec#Assignability)
42+
- [Types Identity - Go Spec](https://go.dev/ref/spec#Type_identity)
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package main
2+
3+
func main() {
4+
f(slice)
5+
// cannot use this because:
6+
// []T is different from ...T
7+
// f(variadic)
8+
}
9+
10+
func f(cb func([]int)) {
11+
cb([]int{1, 2, 3})
12+
}
13+
14+
func slice([]int) {
15+
}
16+
17+
func variadic(...int) {
18+
}

caveats/interface-slice/main.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func main() {
6+
intNumbers := []int{1, 2, 3}
7+
anyNumbers := []any{1, 2, 3}
8+
fmt.Println(1, 2, 3)
9+
fmt.Println(anyNumbers...)
10+
// does not work because slice types do not match
11+
// the ...intNumbers will attempt to convert it to []interface{} and will fail
12+
// fmt.Println(intNumbers...)
13+
14+
// converting each element of the intNumbers slice to any (interface{})
15+
// will make sure the unpacked resulting slice's type is of the same type
16+
var iNumbers = make([]any, len(intNumbers))
17+
for i, num := range intNumbers {
18+
iNumbers[i] = num
19+
}
20+
fmt.Println(iNumbers...)
21+
}

caveats/order-matters/main.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package main
2+
3+
func variadic1(int, string, ...string) {
4+
}
5+
6+
// func variadic2(int, string, ...string, string) {
7+
// }

caveats/reuse-same-array/main.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func main() {
6+
numbers := []int{1, 2, 3, 4, 5}
7+
fmt.Println(numbers)
8+
9+
variadic(numbers...)
10+
fmt.Println(numbers)
11+
}
12+
13+
func variadic(args ...int) {
14+
for i := 0; i < len(args); i++ {
15+
args[i] = (i + 1) * 10
16+
}
17+
}

caveats/zero-arguments/main.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func main() {
6+
variadic("1")
7+
variadic("2", []int{}...)
8+
variadic("3", []int(nil)...)
9+
variadic("4", nil...)
10+
}
11+
12+
func variadic(label string, nums ...int) {
13+
if nums == nil {
14+
fmt.Println(label, "nil")
15+
}
16+
// will always result in at least
17+
// an empty slice (not a nil slice)
18+
fmt.Println(nums)
19+
}

0 commit comments

Comments
 (0)