Learn Golang
  • Learn Go
  • The Basics
    • Installing Go
    • Hello World
  • Language Features
    • Basic Input Output
    • Variable Basics
    • Control Statements
    • Loops
    • Functions
    • Recursion
  • Data Structures
    • Arrays
    • Slices
    • Maps
    • Pointers
    • Structs
  • Other Concepts
    • Sorting
    • Interfaces
    • Generics
    • Goroutines
  • References
Powered by GitBook
On this page
  1. Language Features

Functions

How functions work in golang

PreviousLoopsNextRecursion

Last updated 2 years ago

CtrlK

We've already seen various functions at this point, beginning with the main function. But on this page we will explore various functions including simple functions, functions that return multiple values, anonymous (no-name) functions, variadic functions, and closures.

1. Simple Functions

Functions can be assigned to variables, passed as arguments to functions or returned from functions. This makes the language more flexible. A function declaration begins with the func keyword. The body is wrapped around curly brackets {} and the function can have parameters or chose to omit them.

In the example below, we will define a simple function that solves a quadratic equation using the quadratic formula:

x=−b±b2−4ac2ax = \frac{-b\pm\sqrt{b^2 - 4ac}}{2a}x=2a−b±b2−4ac​​
package main

import (
  "fmt"
  "math"
)

// define a function called solve_quadratic that takes three float values
// and returns a float as the answer
func solve_quadratic(a float64, b float64, c float64) float64 {
  bb := b * b
  quotient := (-1 * b) + math.Sqrt((bb - (4 * a * c)))
  divisor := 2 * a
  ans := quotient / divisor
  return ans
}

func main() {
  a := 1.0
  b := -3.0
  c := -4.0
  // call the solve_quadratic function with some values
  ans1 := solve_quadratic(a, b, c)
  fmt.Println("Ans: ", ans1)
  
  // call the function again with different values
  ans2 := solve_quadratic(-10.5, 3.99, -8.475)
}

The solution above only returns one answer, even though the quadratic formula should return two answers. We will see how to return multiple values next.

2. Functions that return multiple values

The example above only returned one value. However, we can modify the function to return two (or more values) as follows

package main

import "math"

// set the return type of the values
func solve_quadratic(a, b, c float64) (float64, float64) {
  bb := b * b
  q1 := (-1 * b) + math.Sqrt((bb - (4 * a * c)))
  q2 := (-1 * b) - math.Sqrt((bb - (4 * a * c)))
  divisor := 2 * a
  x1 := q1 / divisor
  x2 := q2 / divisor
  // return both x1 and x2
  return x1, x2
}

func main() {
  // we can later call the function as follows
  a, b := solve_quadratic(1.0, -3.0, -4.0)
  // if we are only interested in one value, we can use the underscore
  // to ignore the other. For exmaple
  _, b := solve_quadratic(2.0, -3.5, 5.0)
}
  

3. Anonymous Functions

Anonymous functions do not have a name. They can be useful if/when we need to apply a function to some values, but we don't necessarily want to write out a named function for the task. Here is an example:

package main

import "fmt"

func main() {
  mul := func(a, b, c int) int {
    return a * b * c
  }(19, 11, 7)
  fmt.Println("19 * 11 * 7 = ", mul)
  // prints: 19 * 11 * 7 = 1463
}

4. Variadic functions

A variadic function is one that can be called with any number of parameters. The function also accepts an arbitrary number of arguments. We've already seen a function of this type, the fmt.Println() function, which can take an arbitrary number of arguments. Here is how we can define our own in golang

package main

import "fmt"

// adds all the numbers passed as parameters and returns a total
func adder(nums ...int) int {
  fmt.Print(nums, " ")
  sum := 0
  for _, num := range nums {
    sum += num
  }
  return sum
}

func main() {
 fmt.Println(adder(1, 2, 3, 4))     // prints: 10
 fmt.Println(adder(99, 13))         // prints: 112
 scores := []int{4, 5, 19, 6, 2, 11}
 fmt.Println(adder(scores...))      // prints: 47
}
 

If you already have multiple args in a slice (as in the case of line 18 above), we can apply them to a variadic function using func(slice...) . We will cover slices in detail in the Slices section

5. Closure

The last thing related to functions we would look at is closures. A closure is a concept in programming languages where a function returns another function. In other words, a closure gives you access to an outer function's scope (lexicological environment) from an inner function. (See this Wikipedia article to get an in-depth definition of closures). Here is how golang closures work:

closure_function.go
package main

import "fmt"

// a simple program that takes a seed, and increments the seed
// number by one every time the closure function is called
func incrementor(init int) func() int {
  i := init
  return func() int {
    i++
    return i
  }
}

func main() {
  randSequence := incrementor(23)
  fmt.Println(randSequence())
  fmt.Println(randSequence())
  fmt.Println(randSequence())
  
  anotherSequence := incrementor(2412)
  fmt.Println(randSequence())
  fmt.Println(randSequence())
}
$ go run closure_function.go
24
25
26
2413
2414

Functions in golang are very flexible and allow for extensibility as shown above. In golang, we can define our own type for a function, pass functions as arguments into other functions, and return functions as closures. This level of flexibility in functions is known as first-class functions. To learn more about first-class functions and further ideas in golang, see: https://golangbot.com/first-class-functions/