Post

Day05(函数)

函数

函数定义和调用

在 Go 语言中,函数的定义方式如下:

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

例如,一个简单的加法函数可以这样定义和调用:

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func add(x int, y int) int {
    return x + y
}

func main() {
    result := add(3, 4)
    fmt.Println(result)  // 输出: 7
}

多个返回值

Go 语言支持函数返回多个值,这在处理错误时特别有用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func divide(dividend int, divisor int) (int, error) {
    if divisor == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return dividend / divisor, nil
}

func main() {
    result, err := divide(10, 2)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Result:", result)
    }
}

命名返回值

函数的返回值可以被命名,这使得函数体中的代码更为清晰:

1
2
3
4
5
6
7
8
9
10
11
func addAndMultiply(x, y int) (sum int, product int) {
    sum = x + y
    product = x * y
    return
}

func main() {
    sum, product := addAndMultiply(3, 4)
    fmt.Println("Sum:", sum)          // 输出: Sum: 7
    fmt.Println("Product:", product)  // 输出: Product: 12
}

匿名函数和闭包

Go 语言支持匿名函数和闭包,可以在函数内部定义一个匿名函数并调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
    // 匿名函数
    result := func(x, y int) int {
        return x + y
    }(3, 4)
    fmt.Println(result)  // 输出: 7

    // 闭包
    add := func(x int) int {
        return x + 10
    }
    fmt.Println(add(5))  // 输出: 15
}

方法

在 Go 语言中,函数可以附属于一个类型,这样的函数称为方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
type Rectangle struct {
    width, height int
}

// 方法
func (r Rectangle) Area() int {
    return r.width * r.height
}

func main() {
    rect := Rectangle{width: 10, height: 5}
    fmt.Println("Area:", rect.Area())  // 输出: Area: 50
}

递归函数

函数可以调用自身,这就是递归:

1
2
3
4
5
6
7
8
9
10
func factorial(n int) int {
    if n == 0 {
        return 1
    }
    return n * factorial(n-1)
}

func main() {
    fmt.Println(factorial(5))  // 输出: 120
}

defer 语句

defer语句用于延迟执行某个函数直到当前函数返回,这在资源清理等场景中很有用:

1
2
3
4
5
6
func main() {
    fmt.Println("Start")
    defer fmt.Println("Deferred")
    fmt.Println("End")
    // 输出顺序: Start, End, Deferred
}

函数传参方式

值传递

值传递是指在函数调用时,将实际参数的副本传递给函数。这样,函数内对参数的修改不会影响到函数外的变量。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import "fmt"

func modifyValue(val int) {
    val = 10
}

func main() {
    a := 5
    modifyValue(a)
    fmt.Println(a)  // 输出: 5
}

modifyValue函数修改了参数val的值,但这并不影响函数外的变量a

引用传递(通过指针实现)

引用传递的效果是通过传递指针来实现的。传递指针允许函数修改外部变量的值。

  • 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import "fmt"

func modifyPointer(val *int) {
    *val = 10
}

func main() {
    a := 5
    modifyPointer(&a)
    fmt.Println(a)  // 输出: 10
}

modifyPointer函数接收一个指向int类型的指针,并修改该指针指向的值。由于传递的是指针,函数内的修改会影响到外部变量a

  • 示例对比(为了更清楚地理解值传递和通过指针实现的引用传递)

  • 值传递示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

type Point struct {
    x, y int
}

func modifyPointVal(p Point) {
    p.x = 10
    p.y = 10
}

func main() {
    p := Point{1, 2}
    modifyPointVal(p)
    fmt.Println(p)  // 输出: {1, 2}
}

modifyPointVal函数接收的是Point结构体的副本,因此对p的修改不会影响函数外的变量p

  • 引用传递(通过指针实现)示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

type Point struct {
    x, y int
}

func modifyPointPtr(p *Point) {
    p.x = 10
    p.y = 10
}

func main() {
    p := Point{1, 2}
    modifyPointPtr(&p)
    fmt.Println(p)  // 输出: {10, 10}
}

modifyPointPtr函数接收的是指向Point结构体的指针,因此对p的修改会影响函数外的变量p

总结

  • 值传递:将参数的副本传递给函数。函数内部对参数的修改不会影响到外部变量。
  • 引用传递(通过指针实现):传递参数的指针,使得函数能够修改外部变量的值。

特殊用法

可变参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import "fmt"

// 定义一个可变参数函数
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
}

方法(附属于类型的函数)

方法是附属于某个类型的函数,方法可以有接收者,可以是值类型或指针类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import "fmt"

type Rectangle struct {
    width, height int
}

// 值接收者方法
func (r Rectangle) Area() int {
    return r.width * r.height
}

// 指针接收者方法
func (r *Rectangle) Scale(factor int) {
    r.width *= factor
    r.height *= factor
}

func main() {
    rect := Rectangle{width: 10, height: 5}
    fmt.Println("Area:", rect.Area())  // 输出: Area: 50

    rect.Scale(2)
    fmt.Println("Scaled Area:", rect.Area())  // 输出: Scaled Area: 200
}

高阶函数

高阶函数是指接受函数作为参数或返回函数的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import "fmt"

// 高阶函数,返回一个函数
func makeAdder(x int) func(int) int {
    return func(y int) int {
        return x + y
    }
}

func main() {
    add5 := makeAdder(5)
    fmt.Println(add5(3))  // 输出: 8
    fmt.Println(add5(10)) // 输出: 15
}
This post is licensed under CC BY 4.0 by the author.