Skip to content

Go 语言函数

函数是组织和重用代码的基本单位。Go 语言的函数设计简洁而强大,支持多返回值、命名返回值、可变参数等特性。本章将详细介绍 Go 函数的各种用法。

📋 函数基础

函数声明和定义

go
package main

import "fmt"

// 基本函数语法: func 函数名(参数列表) 返回类型 { 函数体 }
func greet() {
    fmt.Println("Hello, World!")
}

// 带参数的函数
func greetPerson(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

// 带返回值的函数
func add(a, b int) int {
    return a + b
}

// 多个参数,多个返回值
func calculate(a, b int) (int, int, int, int) {
    return a + b, a - b, a * b, a / b
}

func main() {
    // 调用函数
    greet()
    greetPerson("Go")
    
    result := add(5, 3)
    fmt.Printf("5 + 3 = %d\n", result)
    
    sum, diff, product, quotient := calculate(20, 4)
    fmt.Printf("20 和 4 的运算结果: 和=%d, 差=%d, 积=%d, 商=%d\n", 
               sum, diff, product, quotient)
}

函数参数

值传递

go
func main() {
    // Go 语言是值传递
    x := 10
    fmt.Printf("调用前 x = %d\n", x)
    
    modifyValue(x)
    fmt.Printf("调用后 x = %d\n", x)  // x 仍然是 10
    
    // 如果需要修改原值,需要传递指针
    fmt.Printf("调用指针函数前 x = %d\n", x)
    modifyPointer(&x)
    fmt.Printf("调用指针函数后 x = %d\n", x)  // x 变成了 20
}

func modifyValue(num int) {
    num = 100
    fmt.Printf("函数内 num = %d\n", num)
}

func modifyPointer(num *int) {
    *num = 20
    fmt.Printf("函数内 *num = %d\n", *num)
}

切片和映射参数

go
func main() {
    // 切片是引用类型,修改会影响原切片
    numbers := []int{1, 2, 3, 4, 5}
    fmt.Printf("修改前: %v\n", numbers)
    
    modifySlice(numbers)
    fmt.Printf("修改后: %v\n", numbers)
    
    // 映射也是引用类型
    scores := map[string]int{"Alice": 85, "Bob": 92}
    fmt.Printf("修改前: %v\n", scores)
    
    modifyMap(scores)
    fmt.Printf("修改后: %v\n", scores)
}

func modifySlice(slice []int) {
    slice[0] = 100  // 修改第一个元素
    slice = append(slice, 6, 7, 8)  // 注意:append 可能不会影响原切片
}

func modifyMap(m map[string]int) {
    m["Charlie"] = 78  // 添加新元素
    m["Alice"] = 95    // 修改现有元素
}

返回值

多返回值

go
import (
    "errors"
    "fmt"
    "math"
)

func main() {
    // 处理多返回值
    quotient, remainder, err := divide(10, 3)
    if err != nil {
        fmt.Printf("错误: %v\n", err)
    } else {
        fmt.Printf("10 ÷ 3 = %d%d\n", quotient, remainder)
    }
    
    // 忽略某些返回值
    _, remainder2, _ := divide(17, 5)
    fmt.Printf("17 除以 5 的余数: %d\n", remainder2)
    
    // 数学运算函数
    result, isValid := sqrt(16)
    if isValid {
        fmt.Printf("√16 = %.2f\n", result)
    }
    
    result2, isValid2 := sqrt(-4)
    if !isValid2 {
        fmt.Println("负数没有实数平方根")
    }
}

func divide(a, b int) (int, int, error) {
    if b == 0 {
        return 0, 0, errors.New("除数不能为零")
    }
    return a / b, a % b, nil
}

func sqrt(x float64) (float64, bool) {
    if x < 0 {
        return 0, false
    }
    return math.Sqrt(x), true
}

命名返回值

go
func main() {
    // 使用命名返回值的函数
    area, perimeter := rectangleCalculations(5, 3)
    fmt.Printf("矩形面积: %.2f, 周长: %.2f\n", area, perimeter)
    
    // 错误处理示例
    result, err := parseAndCalculate("10", "5")
    if err != nil {
        fmt.Printf("错误: %v\n", err)
    } else {
        fmt.Printf("结果: %d\n", result)
    }
}

// 命名返回值
func rectangleCalculations(length, width float64) (area, perimeter float64) {
    area = length * width
    perimeter = 2 * (length + width)
    return  // 不需要指定返回值,会自动返回命名的变量
}

// 命名返回值在错误处理中很有用
func parseAndCalculate(aStr, bStr string) (result int, err error) {
    var a, b int
    
    // 解析第一个数字
    if a, err = parseInt(aStr); err != nil {
        return  // 相当于 return 0, err
    }
    
    // 解析第二个数字
    if b, err = parseInt(bStr); err != nil {
        return
    }
    
    result = a + b
    return  // 相当于 return result, nil
}

func parseInt(s string) (int, error) {
    // 简单的字符串转整数实现
    if s == "10" {
        return 10, nil
    } else if s == "5" {
        return 5, nil
    }
    return 0, errors.New("无法解析字符串")
}

🔄 可变参数函数

基本可变参数

go
func main() {
    // 可变参数函数调用
    fmt.Printf("无参数调用: %d\n", sum())
    fmt.Printf("单个参数: %d\n", sum(5))
    fmt.Printf("多个参数: %d\n", sum(1, 2, 3, 4, 5))
    
    // 传递切片给可变参数函数
    numbers := []int{10, 20, 30, 40}
    fmt.Printf("传递切片: %d\n", sum(numbers...))  // 使用 ... 展开切片
    
    // 字符串连接示例
    message := concatenate("Hello", " ", "Go", " ", "World", "!")
    fmt.Printf("连接结果: %s\n", message)
    
    // 格式化消息
    formattedMsg := formatMessage("用户 %s 的分数是 %d", "Alice", 95)
    fmt.Println(formattedMsg)
}

// 可变参数函数:计算总和
func sum(numbers ...int) int {
    total := 0
    for _, num := range numbers {
        total += num
    }
    return total
}

// 字符串可变参数
func concatenate(strings ...string) string {
    result := ""
    for _, str := range strings {
        result += str
    }
    return result
}

// 混合参数(固定参数 + 可变参数)
func formatMessage(format string, args ...interface{}) string {
    // 简单的格式化实现
    return fmt.Sprintf(format, args...)
}

高级可变参数用法

go
import "reflect"

func main() {
    // 类型安全的可变参数处理
    printInts(1, 2, 3, 4, 5)
    printStrings("Hello", "World", "Go")
    
    // 通用打印函数
    printValues("混合类型:", 42, "Hello", 3.14, true)
    
    // 统计函数
    stats := calculateStats(85, 92, 78, 96, 88, 91)
    fmt.Printf("统计结果: %+v\n", stats)
}

func printInts(numbers ...int) {
    fmt.Print("整数: ")
    for i, num := range numbers {
        if i > 0 {
            fmt.Print(", ")
        }
        fmt.Print(num)
    }
    fmt.Println()
}

func printStrings(strings ...string) {
    fmt.Print("字符串: ")
    for i, str := range strings {
        if i > 0 {
            fmt.Print(", ")
        }
        fmt.Printf("\"%s\"", str)
    }
    fmt.Println()
}

// 处理任意类型的可变参数
func printValues(prefix string, values ...interface{}) {
    fmt.Print(prefix + " ")
    for i, value := range values {
        if i > 0 {
            fmt.Print(", ")
        }
        fmt.Printf("%v(%T)", value, value)
    }
    fmt.Println()
}

// 统计数据结构
type Statistics struct {
    Count   int
    Sum     float64
    Average float64
    Min     float64
    Max     float64
}

func calculateStats(values ...float64) Statistics {
    if len(values) == 0 {
        return Statistics{}
    }
    
    stats := Statistics{
        Count: len(values),
        Min:   values[0],
        Max:   values[0],
    }
    
    for _, value := range values {
        stats.Sum += value
        if value < stats.Min {
            stats.Min = value
        }
        if value > stats.Max {
            stats.Max = value
        }
    }
    
    stats.Average = stats.Sum / float64(stats.Count)
    return stats
}

🎯 函数作为值

函数变量

go
import "math"

func main() {
    // 函数可以赋值给变量
    var operation func(float64, float64) float64
    
    operation = add_float
    fmt.Printf("加法: %.2f\n", operation(3.5, 2.1))
    
    operation = multiply_float
    fmt.Printf("乘法: %.2f\n", operation(3.5, 2.1))
    
    // 函数切片
    operations := []func(float64, float64) float64{
        add_float,
        subtract_float,
        multiply_float,
        divide_float,
    }
    
    operationNames := []string{"加法", "减法", "乘法", "除法"}
    
    a, b := 10.0, 3.0
    for i, op := range operations {
        result := op(a, b)
        fmt.Printf("%.1f %s %.1f = %.2f\n", a, operationNames[i], b, result)
    }
    
    // 函数映射
    calculator := map[string]func(float64, float64) float64{
        "+": add_float,
        "-": subtract_float,
        "*": multiply_float,
        "/": divide_float,
        "^": math.Pow,
    }
    
    fmt.Println("\n计算器演示:")
    expressions := []struct {
        a, b float64
        op   string
    }{
        {10, 5, "+"},
        {10, 5, "-"},
        {10, 5, "*"},
        {10, 5, "/"},
        {2, 8, "^"},
    }
    
    for _, expr := range expressions {
        if fn, exists := calculator[expr.op]; exists {
            result := fn(expr.a, expr.b)
            fmt.Printf("%.1f %s %.1f = %.2f\n", expr.a, expr.op, expr.b, result)
        }
    }
}

func add_float(a, b float64) float64      { return a + b }
func subtract_float(a, b float64) float64 { return a - b }
func multiply_float(a, b float64) float64 { return a * b }
func divide_float(a, b float64) float64   { return a / b }

高阶函数

go
func main() {
    // 高阶函数:接受函数作为参数
    numbers := []int{1, 2, 3, 4, 5}
    
    // 应用不同的变换函数
    squared := applyTransform(numbers, square)
    fmt.Printf("平方: %v\n", squared)
    
    doubled := applyTransform(numbers, double)
    fmt.Printf("翻倍: %v\n", doubled)
    
    cubed := applyTransform(numbers, func(x int) int { return x * x * x })
    fmt.Printf("立方: %v\n", cubed)
    
    // 过滤函数
    evens := filter(numbers, isEven)
    fmt.Printf("偶数: %v\n", evens)
    
    odds := filter(numbers, isOdd)
    fmt.Printf("奇数: %v\n", odds)
    
    // 归约函数
    sum := reduce(numbers, 0, add_int)
    fmt.Printf("总和: %d\n", sum)
    
    product := reduce(numbers, 1, multiply_int)
    fmt.Printf("乘积: %d\n", product)
    
    // 复合函数
    addThenSquare := compose(square, func(x int) int { return x + 1 })
    result := addThenSquare(5)  // (5+1)^2 = 36
    fmt.Printf("先加1再平方: %d\n", result)
}

// 变换函数:对切片中每个元素应用函数
func applyTransform(slice []int, fn func(int) int) []int {
    result := make([]int, len(slice))
    for i, v := range slice {
        result[i] = fn(v)
    }
    return result
}

// 过滤函数:根据条件过滤元素
func filter(slice []int, predicate func(int) bool) []int {
    var result []int
    for _, v := range slice {
        if predicate(v) {
            result = append(result, v)
        }
    }
    return result
}

// 归约函数:将切片归约为单个值
func reduce(slice []int, initial int, fn func(int, int) int) int {
    result := initial
    for _, v := range slice {
        result = fn(result, v)
    }
    return result
}

// 函数组合
func compose(f, g func(int) int) func(int) int {
    return func(x int) int {
        return f(g(x))
    }
}

// 辅助函数
func square(x int) int         { return x * x }
func double(x int) int         { return x * 2 }
func isEven(x int) bool        { return x%2 == 0 }
func isOdd(x int) bool         { return x%2 != 0 }
func add_int(a, b int) int     { return a + b }
func multiply_int(a, b int) int { return a * b }

🔄 递归函数

基本递归

go
func main() {
    // 阶乘计算
    for i := 0; i <= 10; i++ {
        fmt.Printf("%d! = %d\n", i, factorial(i))
    }
    
    // 斐波那契数列
    fmt.Println("\n斐波那契数列:")
    for i := 0; i <= 15; i++ {
        fmt.Printf("fib(%d) = %d\n", i, fibonacci(i))
    }
    
    // 汉诺塔问题
    fmt.Println("\n汉诺塔移动步骤 (3个盘子):")
    hanoi(3, "A", "C", "B")
}

// 阶乘函数
func factorial(n int) int {
    if n <= 1 {
        return 1
    }
    return n * factorial(n-1)
}

// 斐波那契数列
func fibonacci(n int) int {
    if n <= 1 {
        return n
    }
    return fibonacci(n-1) + fibonacci(n-2)
}

// 汉诺塔问题
func hanoi(n int, from, to, aux string) {
    if n == 1 {
        fmt.Printf("将盘子从 %s 移动到 %s\n", from, to)
        return
    }
    hanoi(n-1, from, aux, to)
    fmt.Printf("将盘子从 %s 移动到 %s\n", from, to)
    hanoi(n-1, aux, to, from)
}

尾递归优化

go
func main() {
    // 普通递归 vs 尾递归
    fmt.Printf("普通递归阶乘 10! = %d\n", factorial(10))
    fmt.Printf("尾递归阶乘 10! = %d\n", factorialTail(10))
    
    // 尾递归斐波那契
    fmt.Printf("尾递归斐波那契 fib(15) = %d\n", fibonacciTail(15))
}

// 尾递归阶乘
func factorialTail(n int) int {
    return factorialHelper(n, 1)
}

func factorialHelper(n, acc int) int {
    if n <= 1 {
        return acc
    }
    return factorialHelper(n-1, n*acc)
}

// 尾递归斐波那契
func fibonacciTail(n int) int {
    return fibonacciHelper(n, 0, 1)
}

func fibonacciHelper(n, a, b int) int {
    if n == 0 {
        return a
    }
    if n == 1 {
        return b
    }
    return fibonacciHelper(n-1, b, a+b)
}

🎯 实际应用示例

数学工具库

go
import "math"

// 数学工具包
type MathUtils struct{}

func NewMathUtils() *MathUtils {
    return &MathUtils{}
}

func main() {
    math := NewMathUtils()
    
    // 几何计算
    fmt.Printf("圆形面积 (半径5): %.2f\n", math.CircleArea(5))
    fmt.Printf("矩形面积 (5x3): %.2f\n", math.RectangleArea(5, 3))
    fmt.Printf("三角形面积 (底5高4): %.2f\n", math.TriangleArea(5, 4))
    
    // 数值计算
    fmt.Printf("最大公约数 (48, 18): %d\n", math.GCD(48, 18))
    fmt.Printf("最小公倍数 (48, 18): %d\n", math.LCM(48, 18))
    fmt.Printf("是否为素数 (17): %t\n", math.IsPrime(17))
    fmt.Printf("是否为素数 (18): %t\n", math.IsPrime(18))
    
    // 统计计算
    data := []float64{85, 92, 78, 96, 88, 91, 79, 95}
    fmt.Printf("平均值: %.2f\n", math.Mean(data))
    fmt.Printf("中位数: %.2f\n", math.Median(data))
    fmt.Printf("标准差: %.2f\n", math.StandardDeviation(data))
}

// 几何计算函数
func (m *MathUtils) CircleArea(radius float64) float64 {
    return math.Pi * radius * radius
}

func (m *MathUtils) RectangleArea(length, width float64) float64 {
    return length * width
}

func (m *MathUtils) TriangleArea(base, height float64) float64 {
    return 0.5 * base * height
}

// 数论函数
func (m *MathUtils) GCD(a, b int) int {
    for b != 0 {
        a, b = b, a%b
    }
    return a
}

func (m *MathUtils) LCM(a, b int) int {
    return (a * b) / m.GCD(a, b)
}

func (m *MathUtils) IsPrime(n int) bool {
    if n < 2 {
        return false
    }
    if n == 2 {
        return true
    }
    if n%2 == 0 {
        return false
    }
    for i := 3; i*i <= n; i += 2 {
        if n%i == 0 {
            return false
        }
    }
    return true
}

// 统计函数
func (m *MathUtils) Mean(data []float64) float64 {
    if len(data) == 0 {
        return 0
    }
    sum := 0.0
    for _, v := range data {
        sum += v
    }
    return sum / float64(len(data))
}

func (m *MathUtils) Median(data []float64) float64 {
    if len(data) == 0 {
        return 0
    }
    
    // 复制并排序数据
    sorted := make([]float64, len(data))
    copy(sorted, data)
    
    // 简单排序
    for i := 0; i < len(sorted)-1; i++ {
        for j := i + 1; j < len(sorted); j++ {
            if sorted[i] > sorted[j] {
                sorted[i], sorted[j] = sorted[j], sorted[i]
            }
        }
    }
    
    n := len(sorted)
    if n%2 == 0 {
        return (sorted[n/2-1] + sorted[n/2]) / 2
    }
    return sorted[n/2]
}

func (m *MathUtils) StandardDeviation(data []float64) float64 {
    if len(data) <= 1 {
        return 0
    }
    
    mean := m.Mean(data)
    sumSquaredDiff := 0.0
    
    for _, v := range data {
        diff := v - mean
        sumSquaredDiff += diff * diff
    }
    
    variance := sumSquaredDiff / float64(len(data)-1)
    return math.Sqrt(variance)
}

🎓 小结

本章我们深入学习了 Go 语言的函数:

  • 函数基础:声明、参数、返回值、命名返回值
  • 可变参数:灵活的参数处理
  • 函数值:函数作为一等公民,高阶函数
  • 递归函数:递归原理和尾递归优化
  • 实际应用:数学工具库的实现

函数是Go语言的核心概念,掌握函数的各种用法对于编写高质量的Go代码至关重要。


接下来,我们将学习 Go 语言函数进阶,包括闭包、匿名函数等高级特性。

函数使用建议

  • 保持函数简短,专注单一职责
  • 使用描述性的函数名和参数名
  • 善用多返回值处理错误
  • 考虑使用命名返回值提高可读性

本站内容仅供学习和研究使用。