Go语言快速入门Go语言快速入门
首页
基础篇
进阶篇
高阶篇
实战篇
Go官方网站
编程指南
首页
基础篇
进阶篇
高阶篇
实战篇
Go官方网站
编程指南
  • 基础篇

    • 🚀 基础篇
    • 第1章 - 环境安装
    • 第2章 - Hello World
    • 第3章 - 变量与常量
    • 第4章 - 数据类型
    • 控制流程
    • 函数
    • 数组与切片
    • Map
    • 结构体
    • 指针

函数

函数是代码复用的基础。Go的函数有一些独特的特性,比如多返回值,超级好用!我记得当年学Java的时候,要返回多个值还得封装成对象,特别麻烦。Go直接支持多返回值,这个设计真的太贴心了!

函数定义

基本语法

func 函数名(参数列表) 返回值类型 {
    // 函数体
    return 返回值
}
// 无参数,无返回值
func sayHello() {
    fmt.Println("Hello!")
}

// 有参数,有返回值
func add(a int, b int) int {
    return a + b
}

// 参数类型相同可以简写
func add(a, b int) int {
    return a + b
}

对比其他语言

// Java
public int add(int a, int b) {
    return a + b;
}
// JavaScript
function add(a, b) {
    return a + b;
}
// Go - 类型在后面,更简洁
func add(a, b int) int {
    return a + b
}

多返回值

Go函数可以返回多个值,这是Go的一大特色!

// 返回两个值
func divide(a, b int) (int, int) {
    quotient := a / b
    remainder := a % b
    return quotient, remainder
}

func main() {
    q, r := divide(17, 5)
    fmt.Printf("17 ÷ 5 = %d 余 %d\n", q, r)  // 17 ÷ 5 = 3 余 2
}

命名返回值

func divide(a, b int) (quotient, remainder int) {
    quotient = a / b
    remainder = a % b
    return  // 直接return,自动返回命名的变量
}

忽略返回值

q, _ := divide(17, 5)  // 只要商,忽略余数

Java程序员注意

Java返回多个值要封装成对象,Go直接返回多个值,省事!

// Java需要创建一个类
public class DivideResult {
    int quotient;
    int remainder;
}

错误处理模式

Go没有异常,用多返回值处理错误:

func readFile(filename string) (string, error) {
    data, err := os.ReadFile(filename)
    if err != nil {
        return "", err  // 返回错误
    }
    return string(data), nil  // nil表示没有错误
}

func main() {
    content, err := readFile("test.txt")
    if err != nil {
        fmt.Println("读取失败:", err)
        return
    }
    fmt.Println(content)
}

这是Go最常见的代码模式,你会写很多 if err != nil!

可变参数

// ...int 表示可以接收任意数量的int参数
func sum(nums ...int) int {
    total := 0
    for _, num := range nums {
        total += num
    }
    return total
}

func main() {
    fmt.Println(sum(1, 2, 3))        // 6
    fmt.Println(sum(1, 2, 3, 4, 5))  // 15
    
    // 传入切片需要展开
    nums := []int{1, 2, 3, 4, 5}
    fmt.Println(sum(nums...))        // 15
}

函数是一等公民

Go的函数可以:

  • 赋值给变量
  • 作为参数传递
  • 作为返回值

函数变量

// 函数赋值给变量
add := func(a, b int) int {
    return a + b
}
fmt.Println(add(1, 2))  // 3

// 函数类型
type Calculator func(int, int) int
var calc Calculator = add
fmt.Println(calc(3, 4))  // 7

函数作为参数

// 高阶函数
func apply(nums []int, fn func(int) int) []int {
    result := make([]int, len(nums))
    for i, n := range nums {
        result[i] = fn(n)
    }
    return result
}

func main() {
    nums := []int{1, 2, 3, 4, 5}
    
    // 传入函数
    doubled := apply(nums, func(n int) int {
        return n * 2
    })
    fmt.Println(doubled)  // [2 4 6 8 10]
    
    squared := apply(nums, func(n int) int {
        return n * n
    })
    fmt.Println(squared)  // [1 4 9 16 25]
}

对比JavaScript

// JavaScript
const doubled = nums.map(n => n * 2);

// Go
doubled := apply(nums, func(n int) int { return n * 2 })

思想是一样的,就是语法不同!

匿名函数和闭包

匿名函数

// 立即执行的匿名函数
func() {
    fmt.Println("我是匿名函数")
}()

// 带参数
func(name string) {
    fmt.Println("Hello,", name)
}("Go")

闭包

闭包可以捕获外部变量:

func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

func main() {
    c := counter()
    fmt.Println(c())  // 1
    fmt.Println(c())  // 2
    fmt.Println(c())  // 3
    
    c2 := counter()  // 新的计数器
    fmt.Println(c2())  // 1
}

闭包的坑

// 错误示范
funcs := []func(){}
for i := 0; i < 3; i++ {
    funcs = append(funcs, func() {
        fmt.Println(i)
    })
}
for _, f := range funcs {
    f()  // 输出: 3 3 3(都是3!)
}

// 正确做法
funcs := []func(){}
for i := 0; i < 3; i++ {
    i := i  // 创建新的变量
    funcs = append(funcs, func() {
        fmt.Println(i)
    })
}
for _, f := range funcs {
    f()  // 输出: 0 1 2
}

递归函数

// 阶乘
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 main() {
    fmt.Println(factorial(5))   // 120
    fmt.Println(fibonacci(10))  // 55
}

init 函数

init 函数在 main 之前自动执行,用于初始化:

package main

import "fmt"

var name string

func init() {
    fmt.Println("init函数执行")
    name = "Go"
}

func main() {
    fmt.Println("main函数执行")
    fmt.Println("name =", name)
}

// 输出:
// init函数执行
// main函数执行
// name = Go

执行顺序:导入包 → 包级别变量 → init函数 → main函数

实战案例:简易计算器

package main

import "fmt"

// 定义运算函数类型
type Operation func(a, b float64) float64

// 运算函数
func add(a, b float64) float64      { return a + b }
func subtract(a, b float64) float64 { return a - b }
func multiply(a, b float64) float64 { return a * b }
func divide(a, b float64) float64 {
    if b == 0 {
        fmt.Println("错误: 除数不能为0")
        return 0
    }
    return a / b
}

// 计算函数
func calculate(a, b float64, op Operation) float64 {
    return op(a, b)
}

func main() {
    a, b := 10.0, 3.0
    
    fmt.Printf("%.1f + %.1f = %.1f\n", a, b, calculate(a, b, add))
    fmt.Printf("%.1f - %.1f = %.1f\n", a, b, calculate(a, b, subtract))
    fmt.Printf("%.1f × %.1f = %.1f\n", a, b, calculate(a, b, multiply))
    fmt.Printf("%.1f ÷ %.1f = %.2f\n", a, b, calculate(a, b, divide))
}

输出:

10.0 + 3.0 = 13.0
10.0 - 3.0 = 7.0
10.0 × 3.0 = 30.0
10.0 ÷ 3.0 = 3.33

实战案例:字符串工具函数

package main

import (
    "fmt"
    "strings"
)

// 判断字符串是否为空
func isEmpty(s string) bool {
    return len(strings.TrimSpace(s)) == 0
}

// 首字母大写
func capitalize(s string) string {
    if len(s) == 0 {
        return s
    }
    return strings.ToUpper(s[:1]) + s[1:]
}

// 字符串重复
func repeat(s string, n int) string {
    return strings.Repeat(s, n)
}

// 反转字符串
func reverse(s string) string {
    runes := []rune(s)
    for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
        runes[i], runes[j] = runes[j], runes[i]
    }
    return string(runes)
}

func main() {
    fmt.Println(isEmpty(""))           // true
    fmt.Println(isEmpty("  "))         // true
    fmt.Println(isEmpty("hello"))      // false
    
    fmt.Println(capitalize("hello"))   // Hello
    fmt.Println(repeat("Go ", 3))      // Go Go Go 
    fmt.Println(reverse("Hello世界"))  // 界世olleH
}

练习

  1. 写一个函数,接收两个数,返回它们的最大值和最小值
  2. 写一个函数,计算切片中所有数字的平均值
  3. 使用闭包实现一个累加器
参考答案
package main

import "fmt"

// 1. 返回最大值和最小值
func minMax(a, b int) (min, max int) {
    if a < b {
        return a, b
    }
    return b, a
}

// 2. 计算平均值
func average(nums []float64) float64 {
    if len(nums) == 0 {
        return 0
    }
    sum := 0.0
    for _, n := range nums {
        sum += n
    }
    return sum / float64(len(nums))
}

// 3. 累加器闭包
func accumulator(initial int) func(int) int {
    sum := initial
    return func(n int) int {
        sum += n
        return sum
    }
}

func main() {
    // 1. 测试minMax
    min, max := minMax(5, 3)
    fmt.Printf("min=%d, max=%d\n", min, max)
    
    // 2. 测试average
    nums := []float64{1, 2, 3, 4, 5}
    fmt.Printf("平均值: %.2f\n", average(nums))
    
    // 3. 测试累加器
    acc := accumulator(0)
    fmt.Println(acc(10))  // 10
    fmt.Println(acc(20))  // 30
    fmt.Println(acc(30))  // 60
}

函数是Go的核心,下一节学习数组与切片!

最近更新: 2025/12/27 13:26
Contributors: 王长安
Prev
控制流程
Next
数组与切片