Skip to main content

Command Palette

Search for a command to run...

Ninth Break: Functions in Go

Declaration, Named and optional Parameters, Multiple values types as Input parameters and Multiple and Named return Types

Published
6 min read
Ninth Break: Functions in Go
J

Hacking Lover, Scripting Addict -my own life is a script after all-

Hi everyone! this is Jimmy , and this is the Ninth article in my series “Breaking Things with Go.” In this series, I document my journey through Jon Bodner’s Second Edition: Learning Go – An Idiomatic Approach to Real-World Go Programming and explore how to use Go in the most practical way I can

in this series the resources are the book itself, go documentation, and any AI model to clarify some things

lets Jump into it

Jump Into A Hole Stickers - Find & Share on GIPHY

Long Time no see, Can’t Live without me ? Kidding chill out
in Today’s break we’ll be going through some topics of Functions in GO

Basic Declaration

I’m not gonna yap about what is functions and why it exist so I will assume that everyone knows what function is and we’ll go from there

let’s start with Basic Function declaration in Go

  • func func_name(Param_name param_type) return_type {//code}

  • if you will return something you have to specify its type and no return needed if you won’t

  • if you need to exit function before its last line (if it doesn’t return anything) you can use return (known as naked-return in Go)

  • if the function returns data you can pass it around directly or you can assign it to variable first then pass it using that variable’s name

so function of simple division should look like

func div(num int, denom int) int{ // takes two integers, and returns int type 
    if denom == 0 {
        return 0
    }
    return num / denom 
}

BTW if there is two parameters of two types declared after each other you can write the type once func div(num, deno int) int {}

and you can just call it div(3, 5) or assign it to variable result:=div(3,5) or pass it around fmt.Println(div(3,5))

Named and Optional Parameters

Go doesn’t support named or optional parameters but we can simulate it using structs with the fields that matches the desired Parameters

struct must be declared on package level

package main

type MyFuncOpts struct {
    FirstName string
    LastName  string
    Age       int
}

func MyFunc(opts MyFuncOpts) error {
    // do something here 
}
func main() {
    MyFunc(MyFuncOpts{ // others are set to their zero value
        LastName: "Patel",
        Age:      50,
    })
    MyFunc(MyFuncOpts{
        FirstName: "Joe",
        LastName:  "Smith",
    })
}

if you found yourself using too much optional and name parameters refactor your functions

Variadic Input Parameters and Slices

variadic input means a function can accept a variable number of arguments of the same type

we indicate variadic input Parameters using three dots ... before the type and it has to be the last parameter

func addTo(base int, vals ...int) []int {
    out := make([]int, 0, len(vals))
    for _, v := range vals {
        out = append(out, base+v)
    }
    return out
}

func main() {
    fmt.Println(addTo(3))             // doesn't loop so it returns out slice empty []
    fmt.Println(addTo(3, 2))          // 5
    fmt.Println(addTo(3, 2, 4, 6, 8)) // 5 7 9 11
    a := []int{2, 4, 6, 8}
    fmt.Println(addTo(3, a...))                 // 5 7 9 11
    fmt.Println(addTo(3, []int{2, 4, 6, 8}...)) // 5 7 9 11
}

Multiple return values

  • go supports multiple return values unlike some programming languages

  • if you return multiple values you have to specify the return type for all values in a parentheses separated by a comma and you must return all of them

  • don't put parentheses around the returned values

returning an error in function → returns error if something goes wrong other wise it will return nil for the error value

func div(num, denom int) (int, int, error) {
    if denom == 0 {
        return 0, 0, errors.New("Can't divide by zero")
    }
    return num / denom, num % denom, nil // return nil if no error returned above
}

func main() {
    result, remainder, err := div(5, 2) // assigned the returned values to variables
    if err != nil { // checks if there is error returned 
        fmt.Println(err)
        os.Exit(1)
    }
    fmt.Println(result, remainder)
}

Note that Multiple returns are Values meaning :

  • in python we can return multiple values but they are returned in a tuple but go returns actual multiple values that each of them need a variable to be assigned to

    • if function returns three values you need to assign them to 3 variables, otherwise you’ll get an error

    • if you wanna ignore value use _ and it will be ignored

    • you can’t use _ and ignore all variables but you can drop the assignment in the first place and nothing happens div(4,2) without assignment but you’ll lose those values

Named return values

we can also name the returned values

  • they are pre-declared variables that we use within the function to hold the return values

  • written comma-separated list within parentheses (even if it's a single value)

  • initialized to their zero value on creation

  • if you don't need to name some of the variables use _ for its name

  • those names are local to the function only and doesn't enforce naming to the returned values assignment on calling

  • you can shadow them if you re-declared them inside the same function again (so if you don't wanna shadow them use = not :=)

here is an example

func div(num, denom int) (result, remainder int, err error) { // same as parameters same types can be combined using comma and write the type once 
    if denom == 0 {
        err = errors.New("Can't divide by zero")
        return result, remainder, err
    }
    result, remainder = num/denom, num%denom // gave a value but not declaration
    return result, remainder, err
}

func main() {
    x, y, z := div(5, 2)
    fmt.Println(x, y, z)
}

those variables are created to pre-declare the variables instead of declaring them inside the function but it is totally fine not to return them because you don't have to

  • you can name variables and then return the values directly without assigning them to variable like this
func div(num, denom int) (result, remainder int, err error) {
    err = nil
    result, remainder = 10, 20
    if denom == 0 {
        return 0, 0, errors.New("Can't divide by zero")
    }
    return num/denom, num%denom, nil
}

func main() {
    x, y, z := div(5, 2)
    fmt.Println(x, y, z) // 2, 1, <nil>
}

don’t get me wrong → don’t have to return them doesn’t mean you can leave them unused (this is an error remember! )

Blank/Naked return

and it is a return statement without specified values, used in a function that has named parameters and it returns the value of the current named variables for example

func sum(a, b int) (result int){
    result = a+b
    return //returns the current value of result which is the summation 
}

func summ(a, b int) (result int){
    return // returns the current value of result which is its zero value of int 0
}
  • don't use them cause they aren't good for readability and will leave developers confused

Takes

  • Go functions are explicit meaning that parameter types, return types, and error handling must always be clear and intentional

  • Variadic parameters are just slices inside the function, but ... is required at the call site to expand a slice

  • Go returns real multiple values (not tuples like python kingdom), and every returned value must be handled or explicitly ignored with _

  • Named and naked returns exist but should be used sparingly due to readability and maintainability concerns

Coming Next

the next break will dive more about function how are they treated, anonymous functions, closures and some cool stuff

so stick around for next break where we will break more stuff

break is over, time to get back to work

feel free to reach out to me / X

Tschüss Freunde

Peace Out GIFs | Tenor

Breaking Things with Go

Part 2 of 10

This series is my learning log while studying Go. I share progress, mistakes, notes, and opinions as I explore the language by breaking things, fixing them, and understanding how Go really works.

Up next

Eighth Break: Control Structures in Go

Expression switches, blank switches, goto statement