Declaring Functions
How to declare a Go function: its parameters, its result type, and the shorthand for parameters that share one type.
func 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) intThey 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
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 24When 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.
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
// failNo 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.
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