Functions
When you need the same code in several places, wrap it in a function: give it a name and call it by that name. main is a function; here is another one:
1package main2 3import "fmt"4 5func greet(name string) {6 fmt.Println("Hello, " + name)7}8 9func main() {10 greet("Lin")11 greet("Chen")12}
Hello, Lin Hello, Chen
func greet(name string) defines a function called greet. name is a parameter, and its type goes after the name: name string. greet("Lin") calls it; "Lin" is the argument, and inside the function it's name. The function can go before or after main.
Return values
A function can work out a value and hand it back: write the type of the result after the parentheses, and use return to give the value back to where it was called:
1package main2 3import "fmt"4 5func total(price int, count int) int {6 return price * count7}8 9func main() {10 fmt.Println(total(25, 4))11 sum := total(12, 3) + total(8, 5)12 fmt.Println(sum)13}
100 76
The call total(25, 4) is itself a value: you can show it, use it in a calculation, or store it in a variable. Parameters of the same type can share it: func total(price, count int) int.
A missing return
Once you say a function returns a string, every path through it needs a return. The Go compiler checks:
1package main2 3import "fmt"4 5func grade(score int) string {6 if score >= 60 {7 return "Pass"8 }9}10 11func main() {12 fmt.Println(grade(72))13}
# command-line-arguments
./prog.go:9:1: missing return./prog.go:9:1: missing return points at line 9, the } that ends grade: when the score is under 60, the function gets there without returning anything. Add return "Retake" before that } and it works.
Several return values
A Go function can return several values at once. Put the result types in parentheses, separate the values after return with commas, and receive them with commas too:
1package main2 3import "fmt"4 5func divmod(a, b int) (int, int) {6 return a / b, a % b7}8 9func main() {10 q, r := divmod(7, 3)11 fmt.Println(q, r)12 hours, minutes := divmod(135, 60)13 fmt.Println(hours, "hours", minutes, "minutes")14}
2 1 2 hours 15 minutes
divmod gives the quotient and the remainder together: 135 minutes is 2 hours 15 minutes.
Dropping values with _
Sometimes you only want one of the values. But receive both and use only one, and you hit an old problem:
1package main2 3import "fmt"4 5func divmod(a, b int) (int, int) {6 return a / b, a % b7}8 9func main() {10 hours, minutes := divmod(135, 60)11 fmt.Println(minutes, "minutes")12}
# command-line-arguments
./prog.go:10:2: declared and not used: hourshours is declared and not used, so it doesn't compile. Write _ for the value you don't want. It's a "throw away" slot, not a variable:
1package main2 3import "fmt"4 5func split(total, people int) (each, left int) {6 each = total / people7 left = total % people8 return9}10 11func main() {12 each, left := split(100, 3)13 fmt.Println("Each:", each, "Left:", left)14 _, left = split(50, 4)15 fmt.Println("Left:", left)16}
Each: 33 Left: 1 Left: 2
split also uses named results: (each, left int) names the two return values. They start at their zero values, you assign to them like ordinary variables, and a bare return at the end hands them back. It's fine now and then in a short function, but return value is usually clearer.
A function gets a copy
What does this show?
1package main2 3import "fmt"4 5func double(n int) {6 n = n * 27}8 9func main() {10 price := 3011 double(price)12 fmt.Println(price)13}
When you call double(price), n gets a copy of the value of price. The function changes n, its copy; price in main is still 30.
When Go calls a function, it copies each argument's value into the parameter. This is called passing by value. Press Step and look at the right: inside addBonus a second level appears, with a score of its own. The two scores share a name but are two separate boxes.
1package main2 3import "fmt"4 5func addBonus(score int) {6 score = score + 107 fmt.Println("In the function:", score)8}9 10func main() {11 score := 8012 addBonus(score)13 fmt.Println("In main:", score)14}
In the function: 90 In main: 80
When the function returns, its level is gone. To get the new value into main, have the function return it and assign it: score = addBonus(score) (then addBonus has to return an int: func addBonus(score int) int, ending with return score). (The other way is a pointer, in lesson 11.)
Any number of arguments
fmt.Println takes one value, two, or many. Your functions can too: put ... before the type of the last parameter, and callers can pass as many values as they like, or none:
1package main2 3import "fmt"4 5func sum(nums ...int) int {6 total := 07 for _, n := range nums {8 total += n9 }10 return total11}12 13func main() {14 fmt.Println(sum(12, 30, 8))15 fmt.Println(sum(99))16 fmt.Println(sum())17}
50 99 0
Inside the function, nums is a slice holding those values (lesson 6 covers slices). for _, n := range nums takes them out one by one into n; the _ in front throws away their positions, which lesson 6 also explains.
Practice
Write the code, then press Check. A hint costs nothing; the answer is there when you need it.
The price after a discount
✓Finish discount: take percent% off price and return the new price (a whole number). It should show 170 and 49.
170 49
1package main2 3import "fmt"4 5func discount(price, percent int) int {6 // work it out here7 return 0 // a placeholder: replace it with the price you work out8}9 10func main() {11 fmt.Println(discount(200, 15))12 fmt.Println(discount(99, 50))13}
Lowest and highest of three temperatures
✓Finish minMax so it returns both the smallest and the largest of three numbers. It should show Low: -3 High: 8 and Low: 15 High: 27.
Low: -3 High: 8 Low: 15 High: 27
1package main2 3import "fmt"4 5func minMax(a, b, c int) (int, int) {6 return 0, 07}8 9func main() {10 low, high := minMax(5, -3, 8)11 fmt.Println("Low:", low, "High:", high)12 low, high = minMax(27, 15, 22)13 fmt.Println("Low:", low, "High:", high)14}
Fix it: the tax that did not stick
✓addTax is meant to add 10% tax to a price, but price in main never changes. Fix it so it shows With tax: 220 and With tax: 60.
With tax: 220 With tax: 60
1package main2 3import "fmt"4 5func addTax(price int) {6 price = price * 110 / 1007}8 9func main() {10 price := 20011 addTax(price)12 fmt.Println("With tax:", price)13 price = 5514 addTax(price)15 fmt.Println("With tax:", price)16}
What you learned
func name(param type) resultType { … }: types go after names, and parameters of the same type can share it,a, b int.returnhands a value back; a function with a result needs areturnon every path, or it's amissing returnerror.- Several results:
func divmod(a, b int) (int, int), received withq, r := divmod(7, 3); write_for one you don't want. - Named results
(each, left int)start at zero values, and a barereturnhands them back. - Pass by value: a parameter is a copy of the argument, so changing it doesn't change the caller's variable; to get a new value,
returnit. - A variadic parameter
nums ...inttakes any number of values and is a slice inside the function.