05 - Becoming a functioning Gopher
Covered in this module:
- functions
- variadic functions
functions
We've been using functions for almost the whole workshop so far, but let's look take a closer look. Go Functions require an explicit parameter list and return type. The function name comes immediately after the func
keyword and then a comma-space separated list of parameters wrapped in parentheses. Each parameter has a name and then a type separated by a space. The return type is specified after the parameter list followed by an enclosure {}
. You must also explicitly return from your function if it has a return type. The returned value must be the same type as the declared return type.
func max(a int, b int) int {
if a >= b {
return a
}
return b
}
Functions without a return type do not need a return and will run through all statements:
func print(message string) {
fmt.Println(message)
}
You invoke a function with the parameters wrapped in parentheses:
package main
import "fmt"
func main() {
prnt("something important")
}
func prnt(message string) {
fmt.Println(message)
}
Functions can have multiple returned values, comma separated and wrapped in parentheses. Return types are still enforced and return
must have the same number of values:
func negativePositive(i float64) (float64, float64) {
return -math.Abs(i), math.Abs(i)
}
return
immediately stops the function. This function will return goodbye
and never print "unreachable code"
.
func signOff() string {
return "goodbye"
fmt.Println("unreachable code")
return "farewell"
}
named return values
Return values can be named. The values are initialized as zero-valued when the function is invoked. A naked return will return the named return values in their current state:
func concat(strs ...string) (output string) {
for _, str := range strs {
output += str
}
return
}
The named returned values can be overridden by explicitly returning values of the correct type:
func concat(strs ...string) (output string) {
for _, str := range strs {
output += str
}
if len(output) >= 21 {
return
}
return "real output too short"
}
variadic functions
The last parameter of a function can take any number of arguments of the same type:
func concat(strs ...string) string {
var output string
for _, str := range strs {
output += str
}
return output
}
capture returned values
When calling a function, you capture the returned values into variables:
package main
import "fmt"
func main() {
strings1 := []string{"A","E","I","O","U","sometimes","Y"}
strings2 := []string{"E","B","N","/","O","Z","N"}
title := concat(strings1...)
var artist string
artist = concat(strings2...)
fmt.Println(title, artist)
}
func concat(strs ...string) (output string) {
for _, str := range strs {
output += str
}
return
}
All values returned from a function must be captured or explicitly ignored using _
func main() {
first, second := someStrings()
third, _ := someStrings()
fourth := someStrings() // compiler throws error here
}
func someStrings() (string, string) {
// snippet
}
Functions can return many values as a tuple, but you sacrifice readability especially in a case where the returned values are not named:
func main() {
year, _, day, hour, min, _ := getDate()
fmt.Println(year, day, hour, min)
}
func getDate() (int, int, int, int, int, int) {
// snippet
return year, month, day, hour, min, sec
}
Note
There may be some instances where it is warranted, but a good rule of thumb is try to avoid return value lists over three values. Part 9 will introduce the struct
type for collecting data into logical groupings.
Hands on!
- In the repo, open the file
./basics/05functions.go
- Complete the TODOs
- Run
make 05
from project root (alternatively, typego run ./05functions.go
) - Example implementation available on
solutions
branch