Declaring Functions

How to declare a Go function: its parameters, its result type, and the shorthand for parameters that share one type.

Syntaxfunc name(a int, b string) int { ... }

A function is a block of code with a name. You run it by writing its name followed by round brackets. The code inside can take values from whoever called it, and hand one value back. Writing a calculation once and calling it from five places means a correction happens in one place.

A declaration has four parts in a fixed order: the keyword func, the name, the parameters in round brackets, then the type of the result. A parameter is a variable that lives only inside the function and gets its value from the caller. An argument is the value the caller actually passes. So func area(w int, h int) int declares two int parameters and promises to hand back one int.

The grouped shorthand

When neighbouring parameters have the same type, you may write the type once, after the last name. These two lines declare the same function:

func area(w int, h int) int
func area(w, h int) int

They mean exactly the same thing to the compiler. Both forms appear in real code, so you need to read both.

What trips people up

The result type goes after the brackets, never before the name. A function that hands nothing back has nothing in that position. Go copies each argument into its parameter, so assigning to a parameter inside the function leaves the caller's variable alone. And if a function declares a result type, every path out of it must end in a return, or the compiler stops with missing return.

Example

Example · go
package main

import "fmt"

// area takes two ints and hands back one int.
// "w, h int" is shorthand for "w int, h int".
func area(w, h int) int {
	return w * h
}

// perimeter is the same declaration written the long way.
func perimeter(w int, h int) int {
	return 2 * (w + h)
}

// describe mixes parameter types and hands back a string.
func describe(name string, w, h int) string {
	return fmt.Sprintf("%s: area %d, perimeter %d", name, area(w, h), perimeter(w, h))
}

func main() {
	fmt.Println(describe("desk", 3, 4))
	fmt.Println(describe("shelf", 10, 2))
}

// Output:
// desk: area 12, perimeter 14
// shelf: area 20, perimeter 24

When to use it

  • Give a repeated calculation one name so a change to it happens in one place.
  • Cut a long main function into three short functions you can read one at a time.
  • Wrap a fiddly rule, such as how a price is rounded, so every caller gets the same answer.

More examples

Several returns in one function

Reaching a return stops the function there and then, so the last line is the only case left once the two tests above have failed. Written this way a rule reads top to bottom. Note the final return: it is not optional, because the declared result type means every path must produce a string.

Example · go
package main

import "fmt"

// grade has one parameter and one result. A function may contain
// as many return statements as it likes; the first one reached ends it.
func grade(score int) string {
	if score >= 70 {
		return "pass"
	}
	if score >= 50 {
		return "resit"
	}
	return "fail"
}

func main() {
	fmt.Println(grade(85))
	fmt.Println(grade(60))
	fmt.Println(grade(20))
}

// Output:
// pass
// resit
// fail

No result, and no parameters

Plenty of functions exist for what they do rather than what they give back: printing, writing a file, closing a connection. Leave the result position empty for those. The empty brackets on countTo3 are still required, in the declaration and at every call.

Example · go
package main

import "fmt"

// banner has one parameter and no result: there is no type
// after the closing bracket.
func banner(title string) {
	fmt.Println("==", title, "==")
}

// countTo3 takes nothing at all. The brackets stay, empty.
func countTo3() {
	for i := 1; i <= 3; i++ {
		fmt.Println(i)
	}
}

func main() {
	banner("start")
	countTo3()
}

// Output:
// == start ==
// 1
// 2
// 3

Discussion

  • Be the first to comment on this lesson.