Functions
Functions are declared with the func
keyword. They can have zero or more arguments, and the types of the arguments come after the names with a space. Functions can also return multiple values, and this is how error checking is done in Go. You can even instantiate the return values of the function in the function definition (only use in short functions).
By default, arguments are passed by value. To pass by reference, you need to take a pointer as the argument to modify the reference.
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func swap(x, y string) (string, string) {
return y, x
}
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
func main() {
fmt.Println(add(42, 13))
fmt.Println(swap("foo", "bar"))
fmt.Println(split(17))
}
Functions can also be saved as variables and passed to other functions.
package main
import (
"fmt"
"math"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
Closures
Closures are functions that reference variables outside of the function body. In the below example, the inner function of adder
has access to its own sum.
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
// 0 0
// 1 -2
// 3 -6
// 6 -12
// 10 -20
// 15 -30
// 21 -42
// 28 -56
// 36 -72
// 45 -90
Generics
Functions can also take generic types with the below syntax. In the below example the generic type must implement the comparable
constraint, meaning it has the ==
and !=
operators.
func Index[T comparable](s []T, x T) int {
for i, v := range s {
// v and x are type T, which has the comparable
// constraint, so we can use == here.
if v == x {
return i
}
}
return -1
}