Functions

Syntax

The syntax for function is really simple in Go, it starts with func

1
2
3
4
// definition
func eval(a, b int, op string) int {
//function block
}

To define a math operator function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import "fmt"

func eval2(a, b int, op string) int {
switch op {
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
return a / b
case "%":
return a % b
default:
panic("Operator Not Supported: " + op)
}
}

func main() {
fmt.Println(eval2(3, 2, "%"))
}

Return Multiple Results

Similar to Python, Go functions can return multiple results

1
2
3
func div(a, b int) (int, int){
return a/b, a%b
}

The results will be

1
2 1

We may also assign names to the returned value

1
2
3
4
5
6
7
8
9
10
func div(a, b int) (q, r int) {
q = a / b
r = a % b
return
}

func main(){
q, r := div(13, 4)
fmt.Println(q, r)
}

The output results will be

1
3 1

What if the function returns multiple results, but we just need to use one of them? As Go is strict on varialbe definition.
Once a variable is defined, it must be used in the code. We could use _ to take the unwanted result

1
2
3
4
5
6
7
8
9
10
func div(a, b int) (q, r int) {
q = a / b
r = a % b
return
}

func main(){
q, _ := div(13, 4)
fmt.Println(q)
}

We could use this feature to rewrite the operator function with more informative error message

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func eval3(a, b int, op string) (int, error) {
switch op {
case "+":
return a + b, nil
case "-":
return a - b, nil
case "*":
return a * b, nil
case "/":
return a / b, nil
case "%":
return a % b, nil
default:
return -1, fmt.Errorf("Operator Not Recongized: %s", op)
}
}

func main(){
if res, err := eval3(7, 5, "x"); err != nil {
fmt.Println(err)
} else {
fmt.Println(res)
}
}

The output will be:

1
Operator Not Recongized: x

Functional Programming

Go supports functional programming, we could refactor the above function with nested function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"fmt"
"math"
"reflect"
"runtime"
)

func apply(op func(int, int) int, a, b int) int {
//below shows how to get the function name
p := reflect.ValueOf(op).Pointer()
//get the function pointer with reflect package
opName := runtime.FuncForPC(p).Name()
//get the function name
fmt.Printf("Calling Function %s with args (%d, %d) and results = %d",
opName, a, b, op(a, b))
return op(a, b)
}

func pow(a, b int) int {
return int(math.Pow(float64(a), float64(b)))
}

func main() {
apply(pow, 8, 3)
}

The output will be:

1
Calling Function main.pow with args (8, 3) and results = 512

In the output above, main is the package name, pow is the function name.

Alternatively, we could invoke apply with anonymous function

1
2
3
4
5
func main() {
apply(func(a int, b int) int {
return int(math.Pow(float64(a), float64(b)))
}, 7, 6)
}

The output will be:

1
Calling Function main.main.func1 with args (7, 6) and results = 117649

The first main is the package name, the second main is the function name, since it’s invoked in main function. func1 is due to anonymous function.

Unfortunately, Go doesn’t have something fancy such as lambda in Python or Java.

Go *args

In Go, there are something similar to Non-Keyword Arguments *args in Python. We could use ... in parameters in function definition.

1
2
3
4
5
6
7
8
9
10
11
func mysum(numbers ...int) int {
res := 0
for i := range numbers {
res += numbers[i]
}
return res
}

func main(){
fmt.Println(mysum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
}

The output results will be:

1
55

To summarize

  • The returned type is at the back of function declaration
  • Can return multiple values
  • A function can take other functions as parameters
  • No default parameters or optional parameters
  • Can use ... to declare variable parameters, similar to *args in Python