第3课 函数与多返回值
学习目标
- 掌握Go语言中函数的定义与基本调用
- 理解并熟练运用函数的多返回值特性
- 学会使用命名返回值简化代码
- 了解可变参数函数的使用方法
- 掌握函数作为值的基本用法
核心概念
1. 函数的基本定义
在Go中,函数使用func关键字定义,就像一个“加工厂”,接受输入参数,经过处理后返回结果。
// 函数定义格式
func 函数名(参数列表) 返回类型 {
// 函数体
return 返回值
}
2. 多返回值 - Go的独特特性
Go函数可以返回多个值,这是Go语言的一大特色。特别适合同时返回结果和错误信息。
3. 命名返回值
可以在函数定义时给返回值命名,这样函数体内可以直接使用这些变量,最后使用return关键字时可以不带任何变量(称为“裸返回”)。
4. 可变参数函数
使用...语法定义可以接受任意数量参数的函数。
代码示例
示例1:基础函数与多返回值
package main
import "fmt"
// 计算圆的面积和周长 - 返回两个值
func circleProperties(radius float64) (float64, float64) {
area := 3.14159 * radius * radius // 面积 = π * r²
circumference := 2 * 3.14159 * radius // 周长 = 2 * π * r
return area, circumference
}
// 带错误检查的除法函数
func safeDivide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return a / b, nil
}
func main() {
// 调用多返回值函数
area, circum := circleProperties(5.0)
fmt.Printf("半径为5的圆:面积=%.2f, 周长=%.2f\n", area, circum)
// 使用空白标识符忽略不需要的返回值
areaOnly, _ := circleProperties(3.0)
fmt.Printf("半径为3的圆面积: %.2f\n", areaOnly)
// 使用带错误检查的函数
result, err := safeDivide(10, 0)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println("结果:", result)
}
result, err = safeDivide(10, 2)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Printf("10 / 2 = %.1f\n", result)
}
}
示例2:命名返回值与可变参数
package main
import "fmt"
// 命名返回值的函数
func rectangleProperties(length, width float64) (area, perimeter float64) {
area = length * width // 直接使用命名返回值变量
perimeter = 2 * (length + width)
return // 裸返回,自动返回上面计算的值
}
// 可变参数函数 - 计算任意个数数字的平均值
func average(numbers ...float64) float64 {
if len(numbers) == 0 {
return 0
}
total := 0.0
for _, num := range numbers {
total += num
}
return total / float64(len(numbers))
}
// 带命名返回值和错误检查的函数
func parseAge(ageStr string) (age int, err error) {
// 这里简化处理,实际应使用strconv包解析
if ageStr == "" {
return 0, fmt.Errorf("年龄字符串不能为空")
}
return 25, nil // 示例返回固定值
}
func main() {
// 使用命名返回值函数
area, perimeter := rectangleProperties(5, 3)
fmt.Printf("长方形(5x3): 面积=%.1f, 周长=%.1f\n", area, perimeter)
// 使用可变参数函数
fmt.Printf("平均值: %.2f\n", average(1, 2, 3, 4, 5))
fmt.Printf("平均值: %.2f\n", average(10, 20))
fmt.Printf("平均值: %.2f\n", average()) // 无参数
// 将切片传递给可变参数函数
scores := []float64{85, 92, 78, 90, 88}
fmt.Printf("平均分: %.1f\n", average(scores...)) // 使用...展开切片
}
示例3:函数作为值
package main
import (
"fmt"
"strings"
)
// 函数作为参数
func applyToStrings(strs []string, operation func(string) string) []string {
result := make([]string, len(strs))
for i, s := range strs {
result[i] = operation(s)
}
return result
}
func main() {
// 定义匿名函数
toUpper := func(s string) string {
return strings.ToUpper(s)
}
toLower := func(s string) string {
return strings.ToLower(s)
}
names := []string{"Alice", "Bob", "Charlie", "David"}
// 使用函数作为参数
upperNames := applyToStrings(names, toUpper)
fmt.Println("大写:", upperNames)
lowerNames := applyToStrings(names, toLower)
fmt.Println("小写:", lowerNames)
// 直接传递匿名函数
prefixNames := applyToStrings(names, func(s string) string {
return "Mr. " + s
})
fmt.Println("添加前缀:", prefixNames)
}
实践练习
练习1:基础函数练习
要求:编写一个函数calculateRectangle,接受长方形的长和宽作为参数,返回面积和周长。在main函数中调用该函数并打印结果。
预期输出:
长方形(长=8, 宽=5): 面积=40, 周长=26
练习2:错误处理练习
要求:编写函数calculateSquareRoot,接受一个float64参数,返回它的平方根和错误。如果输入为负数,返回错误信息"不能计算负数的平方根"。在main函数中分别测试正数、负数和零的情况。
预期输出:
9的平方根: 3.00
-4的平方根: 错误: 不能计算负数的平方根
0的平方根: 0.00
练习3:可变参数练习
要求:编写函数findMinMax,接受任意数量的整数,返回其中的最小值和最大值。使用可变参数实现。在main函数中测试不同数量的参数。
预期输出:
findMinMax(3, 7, 1, 9, 4) -> 最小值: 1, 最大值: 9
findMinMax(10, 20) -> 最小值: 10, 最大值: 20
findMinMax(5) -> 最小值: 5, 最大值: 5
常见错误
1. 忽略多返回值
// 错误:忽略了第二个返回值
result, _ := someFunction()
// 正确:如果确实不需要,使用空白标识符_忽略
2. 混淆命名返回值和裸返回
// 错误示例
func badExample() (result int) {
result = 10
return 20 // 这会返回20,而不是命名返回值result的10
}
// 正确示例
func goodExample() (result int) {
result = 10
return // 返回result的值10
}
3. 可变参数类型错误
// 错误:混合不同类型的参数
func wrongVariadic(args ...interface{}) {
// 这样会失去类型安全性
}
// 正确:明确参数类型
func rightVariadic(nums ...int) {
// 类型安全
}
4. 函数作为值时的常见误解
// 错误:试图直接调用函数值的函数
func add(a, b int) int { return a + b }
var operation func(int, int) int = add
// 错误: operation.Method() - 函数没有方法
// 正确:直接调用
result := operation(1, 2)
小结
- 函数定义:使用
func关键字,可以定义参数和返回值类型 - 多返回值:Go函数可以返回多个值,特别适合同时返回结果和错误
- 命名返回值:在函数定义时命名返回值,可以简化代码并提高可读性
- 可变参数:使用
...语法定义接受任意数量参数的函数 - 函数作为值:Go中函数是一等公民,可以赋值给变量、作为参数传递
关键要点:
- 多返回值是Go处理错误的惯用方式
- 命名返回值可以减少重复的return语句
- 可变参数提供了处理不确定数量参数的灵活性
- 函数作为值使得代码更加模块化和可复用
通过本课学习,你应该能够编写基本的Go函数,使用多返回值处理正常结果和错误情况,并理解Go函数的高级特性。这些知识将为后续学习并发编程打下坚实基础。
练习编辑器
go
Loading...