How To Define Functions in Google Go
A program can be broken down into modules that each perform a specific function. These modules interact with each other to perform the entire functionality of the program. Functions are the basis of modular programming in Google Go.
In Google Go, a function is declared using the keyword func as shown below,
func [function name] ([param1 declaration], [param2 declaration],...) (ret1 declaration, ret2 declaration, ...){
//body of the function
}
The function arguments declaration (param1) and return values declaration (ret1) is similar to variable declaration except the var keyword is not used. (See How To Define Variables In Google Go)
func min(x int, y int) int {
if x < y {
return x
}
return y
}
In Google Go, it is necessary that the opening brace { of the scope should be placed on the same line as the function declaration else you will get a compilation error.
func main()
{ //Wrong
fmt.Println("Hello World")
}
func main() { //Correct
fmt.Println("Hello World")
}
One of Go’s unusual features is that functions and methods can return multiple values. Multiple return values are declared after the argument list and separated by a comma as shown below.
package main
import "fmt"
func calc(a int, b int) (add int, sub int){
add = a + b
sub = a - b
return
}
func main(){
a := 100
b := 50
add, sub := calc(a, b)
fmt.Println("Addition = ", add);
fmt.Println("Subtraction = ", sub);
}
The return or result “parameters” of a Go function can be given names and used as regular variables, just like the incoming parameters. When named, they are initialized to the zero values for their types when the function begins; if the function executes a return statement with no arguments, the current values of the result parameters are used as the returned values.
Defer
Go’s defer statement schedules a function call to be run immediately before the function executing the defer returns. It’s an unusual but effective way to deal with situations such as resources that must be released regardless of which path a function takes to return. The canonical examples are unlocking a mutex or closing a file.
// Contents returns the file's contents as a string.
func Contents(filename string) (string, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0)
if err != nil {
return "", err
}
defer f.Close() // f.Close will run when we're finished.
var result []byte
buf := make([]byte, 100)
for {
n, err := f.Read(buf[0:])
result = bytes.Add(result, buf[0:n])
if err != nil {
if err == os.EOF {
break
}
return "", err // f will be closed if we return here.
}
}
return string(result), nil // f will be closed if we return here.
}
Deferring a function like this has two advantages. First, it guarantees that you will never forget to close the file, a mistake that’s easy to make if you later edit the function to add a new return path. Second, it means that the close sits near the open, which is much clearer than placing it at the end of the function.
The arguments to the deferred function are evaluated when the defer executes, not when the call executes. Besides avoiding worries about variables changing values as the function executes, this means that a single deferred call site can defer multiple function executions.
Here’s a silly example.
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
Deferred functions are executed in LIFO order, so this code will cause 4 3 2 1 0 to be printed when the function returns.
