第5课:Go 函数与方法

【腾讯云】语音识别准确率高,支持多语种,多场景,限时特惠,最低14.9元起

推广

【腾讯云】语音识别准确率高,支持多语种,多场景,限时特惠,最低14.9元起

Go 函数与方法

函数基础

函数定义语法

func functionName(parameter1 type1, parameter2 type2) returnType {
    // 函数体
    return value
}

基本函数示例

package main

import "fmt"

// 无参数无返回值
func sayHello() {
    fmt.Println("Hello, World!")
}

// 有参数无返回值
func greet(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

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

// 多个参数相同类型
func multiply(a, b, c int) int {
    return a * b * c
}

func main() {
    sayHello()
    greet("Go语言")
    result := add(3, 5)
    fmt.Printf("3 + 5 = %d\n", result)
    
    product := multiply(2, 3, 4)
    fmt.Printf("2 * 3 * 4 = %d\n", product)
}

多返回值

基本多返回值

package main

import (
    "fmt"
    "errors"
)

// 返回两个值
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("除数不能为零")
    }
    return a / b, nil
}

// 返回多个相同类型的值
func getNameAndAge() (string, int) {
    return "张三", 25
}

// 命名返回值
func calculate(a, b int) (sum, product, difference int) {
    sum = a + b
    product = a * b
    difference = a - b
    return // 自动返回命名的返回值
}

func main() {
    // 接收多个返回值
    result, err := divide(10, 3)
    if err != nil {
        fmt.Printf("错误: %v\n", err)
    } else {
        fmt.Printf("结果: %.2f\n", result)
    }
    
    // 忽略某个返回值
    name, _ := getNameAndAge()
    fmt.Printf("姓名: %s\n", name)
    
    // 命名返回值
    s, p, d := calculate(10, 3)
    fmt.Printf("和: %d, 积: %d, 差: %d\n", s, p, d)
}

可变参数

可变参数函数

package main

import "fmt"

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

// 混合参数
func greetAll(greeting string, names ...string) {
    for _, name := range names {
        fmt.Printf("%s, %s!\n", greeting, name)
    }
}

// 传递切片给可变参数
func printNumbers(numbers ...int) {
    for i, num := range numbers {
        fmt.Printf("numbers[%d] = %d\n", i, num)
    }
}

func main() {
    // 调用可变参数函数
    fmt.Printf("sum() = %d\n", sum())
    fmt.Printf("sum(1) = %d\n", sum(1))
    fmt.Printf("sum(1, 2, 3) = %d\n", sum(1, 2, 3))
    fmt.Printf("sum(1, 2, 3, 4, 5) = %d\n", sum(1, 2, 3, 4, 5))
    
    // 混合参数
    greetAll("Hello", "Alice", "Bob", "Charlie")
    
    // 传递切片
    numbers := []int{1, 2, 3, 4, 5}
    printNumbers(numbers...) // 展开切片
}

函数作为值

函数类型

package main

import "fmt"

// 定义函数类型
type Operation func(int, int) int

// 实现不同的操作函数
func add(a, b int) int {
    return a + b
}

func subtract(a, b int) int {
    return a - b
}

func multiply(a, b int) int {
    return a * b
}

// 接受函数作为参数
func calculate(a, b int, op Operation) int {
    return op(a, b)
}

// 返回函数
func getOperation(operator string) Operation {
    switch operator {
    case "+":
        return add
    case "-":
        return subtract
    case "*":
        return multiply
    default:
        return nil
    }
}

func main() {
    // 函数作为变量
    var op Operation = add
    result := op(3, 5)
    fmt.Printf("3 + 5 = %d\n", result)
    
    // 函数作为参数
    result = calculate(10, 3, subtract)
    fmt.Printf("10 - 3 = %d\n", result)
    
    // 获取函数
    multiplyOp := getOperation("*")
    if multiplyOp != nil {
        result = multiplyOp(4, 6)
        fmt.Printf("4 * 6 = %d\n", result)
    }
}

匿名函数和闭包

匿名函数

package main

import "fmt"

func main() {
    // 匿名函数直接调用
    result := func(a, b int) int {
        return a + b
    }(3, 5)
    fmt.Printf("匿名函数结果: %d\n", result)
    
    // 匿名函数赋值给变量
    square := func(x int) int {
        return x * x
    }
    fmt.Printf("5的平方: %d\n", square(5))
    
    // 匿名函数作为参数
    numbers := []int{1, 2, 3, 4, 5}
    processNumbers(numbers, func(x int) int {
        return x * 2
    })
}

func processNumbers(numbers []int, processor func(int) int) {
    for _, num := range numbers {
        result := processor(num)
        fmt.Printf("处理 %d 得到 %d\n", num, result)
    }
}

闭包

package main

import "fmt"

// 返回闭包函数
func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

// 闭包捕获外部变量
func multiplier(factor int) func(int) int {
    return func(x int) int {
        return x * factor
    }
}

// 闭包修改外部变量
func accumulator() func(int) int {
    sum := 0
    return func(x int) int {
        sum += x
        return sum
    }
}

func main() {
    // 计数器闭包
    c1 := counter()
    c2 := counter()
    
    fmt.Printf("c1: %d\n", c1()) // 1
    fmt.Printf("c1: %d\n", c1()) // 2
    fmt.Printf("c2: %d\n", c2()) // 1
    fmt.Printf("c1: %d\n", c1()) // 3
    
    // 乘法器闭包
    double := multiplier(2)
    triple := multiplier(3)
    
    fmt.Printf("double(5) = %d\n", double(5)) // 10
    fmt.Printf("triple(5) = %d\n", triple(5)) // 15
    
    // 累加器闭包
    acc := accumulator()
    fmt.Printf("acc(1) = %d\n", acc(1)) // 1
    fmt.Printf("acc(2) = %d\n", acc(2)) // 3
    fmt.Printf("acc(3) = %d\n", acc(3)) // 6
}

方法

方法定义

package main

import (
    "fmt"
    "math"
)

// 定义结构体
type Circle struct {
    Radius float64
}

type Rectangle struct {
    Width, Height float64
}

// 为Circle定义方法
func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * c.Radius
}

// 为Rectangle定义方法
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

func main() {
    circle := Circle{Radius: 5}
    rectangle := Rectangle{Width: 4, Height: 6}
    
    fmt.Printf("圆形面积: %.2f\n", circle.Area())
    fmt.Printf("圆形周长: %.2f\n", circle.Perimeter())
    
    fmt.Printf("矩形面积: %.2f\n", rectangle.Area())
    fmt.Printf("矩形周长: %.2f\n", rectangle.Perimeter())
}

指针接收者 vs 值接收者

package main

import "fmt"

type Counter struct {
    count int
}

// 值接收者方法(不能修改原始值)
func (c Counter) GetCount() int {
    return c.count
}

func (c Counter) IncrementValue() {
    c.count++ // 只修改副本
}

// 指针接收者方法(可以修改原始值)
func (c *Counter) IncrementPointer() {
    c.count++
}

func (c *Counter) Reset() {
    c.count = 0
}

func main() {
    counter := Counter{count: 0}
    
    fmt.Printf("初始值: %d\n", counter.GetCount())
    
    // 值接收者方法不会修改原始值
    counter.IncrementValue()
    fmt.Printf("值接收者后: %d\n", counter.GetCount()) // 仍然是0
    
    // 指针接收者方法会修改原始值
    counter.IncrementPointer()
    fmt.Printf("指针接收者后: %d\n", counter.GetCount()) // 变成1
    
    counter.IncrementPointer()
    counter.IncrementPointer()
    fmt.Printf("多次增加后: %d\n", counter.GetCount()) // 变成3
    
    counter.Reset()
    fmt.Printf("重置后: %d\n", counter.GetCount()) // 变成0
}

方法集

package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

// 值接收者方法
func (p Person) GetName() string {
    return p.Name
}

// 指针接收者方法
func (p *Person) SetName(name string) {
    p.Name = name
}

func (p *Person) Birthday() {
    p.Age++
}

func main() {
    // 值类型
    person1 := Person{Name: "Alice", Age: 25}
    fmt.Printf("姓名: %s\n", person1.GetName())
    
    // Go会自动转换为指针调用指针接收者方法
    person1.SetName("Alice Smith")
    person1.Birthday()
    fmt.Printf("修改后: %+v\n", person1)
    
    // 指针类型
    person2 := &Person{Name: "Bob", Age: 30}
    fmt.Printf("姓名: %s\n", person2.GetName()) // Go会自动解引用
    
    person2.SetName("Bob Johnson")
    person2.Birthday()
    fmt.Printf("修改后: %+v\n", *person2)
}

接口

接口定义和实现

package main

import "fmt"

// 定义接口
type Shape interface {
    Area() float64
    Perimeter() float64
}

type Drawable interface {
    Draw()
}

// 组合接口
type DrawableShape interface {
    Shape
    Drawable
}

// 实现接口的结构体
type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14159 * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * 3.14159 * c.Radius
}

func (c Circle) Draw() {
    fmt.Printf("绘制半径为%.2f的圆形\n", c.Radius)
}

type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

func (r Rectangle) Draw() {
    fmt.Printf("绘制%gx%g的矩形\n", r.Width, r.Height)
}

// 使用接口的函数
func printShapeInfo(s Shape) {
    fmt.Printf("面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
}

func drawShape(d Drawable) {
    d.Draw()
}

func processDrawableShape(ds DrawableShape) {
    printShapeInfo(ds)
    drawShape(ds)
}

func main() {
    circle := Circle{Radius: 5}
    rectangle := Rectangle{Width: 4, Height: 6}
    
    // 接口的多态性
    shapes := []Shape{circle, rectangle}
    for _, shape := range shapes {
        printShapeInfo(shape)
    }
    
    // 组合接口
    processDrawableShape(circle)
    processDrawableShape(rectangle)
}

空接口

package main

import "fmt"

// 空接口可以存储任何类型的值
func printAnything(value interface{}) {
    fmt.Printf("值: %v, 类型: %T\n", value, value)
}

func processValues(values ...interface{}) {
    for i, value := range values {
        fmt.Printf("参数%d: %v (类型: %T)\n", i, value, value)
    }
}

func main() {
    // 空接口可以接受任何类型
    printAnything(42)
    printAnything("Hello")
    printAnything(3.14)
    printAnything([]int{1, 2, 3})
    printAnything(map[string]int{"a": 1})
    
    // 可变参数的空接口
    processValues(1, "hello", 3.14, true, []string{"a", "b"})
    
    // 空接口切片
    var items []interface{}
    items = append(items, 1, "two", 3.0, true)
    
    for i, item := range items {
        fmt.Printf("items[%d] = %v\n", i, item)
    }
}

错误处理

错误接口

package main

import (
    "errors"
    "fmt"
)

// error是一个内置接口
// type error interface {
//     Error() string
// }

// 自定义错误类型
type ValidationError struct {
    Field   string
    Message string
}

func (e ValidationError) Error() string {
    return fmt.Sprintf("验证错误 - %s: %s", e.Field, e.Message)
}

// 返回错误的函数
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("除数不能为零")
    }
    return a / b, nil
}

func validateAge(age int) error {
    if age < 0 {
        return ValidationError{
            Field:   "age",
            Message: "年龄不能为负数",
        }
    }
    if age > 150 {
        return ValidationError{
            Field:   "age",
            Message: "年龄不能超过150岁",
        }
    }
    return nil
}

func main() {
    // 基本错误处理
    result, err := divide(10, 0)
    if err != nil {
        fmt.Printf("错误: %v\n", err)
    } else {
        fmt.Printf("结果: %.2f\n", result)
    }
    
    // 自定义错误处理
    if err := validateAge(-5); err != nil {
        fmt.Printf("验证失败: %v\n", err)
        
        // 类型断言检查具体错误类型
        if ve, ok := err.(ValidationError); ok {
            fmt.Printf("字段: %s, 消息: %s\n", ve.Field, ve.Message)
        }
    }
    
    if err := validateAge(25); err != nil {
        fmt.Printf("验证失败: %v\n", err)
    } else {
        fmt.Println("年龄验证通过")
    }
}

defer语句

defer基础

package main

import "fmt"

func deferExample() {
    fmt.Println("开始执行函数")
    
    defer fmt.Println("这是第一个defer")
    defer fmt.Println("这是第二个defer")
    defer fmt.Println("这是第三个defer")
    
    fmt.Println("函数主体执行")
    
    // defer按LIFO顺序执行
    // 输出顺序:
    // 开始执行函数
    // 函数主体执行
    // 这是第三个defer
    // 这是第二个defer
    // 这是第一个defer
}

func main() {
    deferExample()
}

defer的实际应用

package main

import (
    "fmt"
    "os"
)

// 文件操作示例
func readFile(filename string) error {
    file, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer file.Close() // 确保文件被关闭
    
    // 读取文件内容
    // ...
    
    return nil
}

// 资源清理示例
func processData() {
    fmt.Println("开始处理数据")
    defer fmt.Println("数据处理完成,清理资源")
    
    // 模拟数据处理
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("捕获到panic: %v\n", r)
        }
    }()
    
    // 可能发生panic的代码
    // panic("模拟错误")
    
    fmt.Println("数据处理中...")
}

func main() {
    processData()
}

总结

本课我们深入学习了Go语言的函数和方法:

  1. 函数基础:定义、参数、返回值
  2. 多返回值:错误处理模式
  3. 可变参数:灵活的参数传递
  4. 函数作为值:高阶函数和函数类型
  5. 匿名函数和闭包:函数式编程特性
  6. 方法:为类型定义行为
  7. 接口:定义契约,实现多态
  8. 错误处理:Go的错误处理机制
  9. defer语句:延迟执行和资源清理

下一课预告

在下一课中,我们将学习Go语言的并发编程,包括:

  • Goroutine的使用
  • Channel通信机制
  • Select语句
  • 并发模式和最佳实践

💡 小贴士:理解接口是Go语言的核心概念,它实现了鸭子类型(duck typing),使得Go具有很强的表达能力和灵活性。

Vue3 + TypeScript 企业级项目实战

课程推荐

Vue3 + TypeScript 企业级项目实战
Python 全栈开发工程师培训

热门课程

Python 全栈开发工程师培训

📚 文章对你有帮助?请关注我的公众号,万分感谢!

获取更多优质技术文章,第一时间掌握最新技术动态

关注公众号

关注公众号

第一时间获取最新技术文章

添加微信

添加微信

技术交流 · 问题答疑 · 学习指导

评论讨论

欢迎留下你的想法和建议