一架梯子,一头程序猿,仰望星空!

go语言函数


本章介绍函数的定义和用法

  • 函数支持0个或者多个参数
  • 函数支持0个或者多个返回值

1. 基本函数定义

语法:

func 函数名(参数列表) (返回值类型列表) {
}

例子:

package main

import "fmt"

// 定义add函数,接受两个int参数,返回值是int类型
func add(x int, y int) int {
    return x + y
}

func main() {
    // 调用函数add, 然后调用Println函数打印返回值
    fmt.Println(add(42, 13))
}

2. 返回多个值的函数

go语言的函数允许返回多个值

例子:

package main

import "fmt"

// 定义swap函数,接受x,y两个参数,swap函数的作用是交换两个参数值
// 连续多个参数的类型一致的话,可以用逗号分隔变量,仅在最后一个变量书写数据类型
// 返回两个string类型的值
func swap(x, y string) (string, string) {
    // 返回多个值,用逗号分隔
    return y, x
}

func main() {
    // 调用swap函数,并且接受两个返回值,按顺序传递给a和b变量
    a, b := swap("hello", "world")
    fmt.Println(a, b)
}

3. 返回命名参数值

我们可以给函数返回值定义命名参数。

例子:

package main

import "fmt"

// 定义split函数
// 定义x,y两个int类型的返回值参数
func split(sum int) (x, y int) {
    // 给x返回值参数赋值
    x = sum * 4 / 9
    // 给y返回值参数赋值
    y = sum - x
    // 直接return,就可以返回x,y参数值
    return
}

func main() {
    fmt.Println(split(17))
}

4.忽略参数返回值

函数可以返回多个值,有时候我们只想要其中一个值,可以通过 _ 下划线符号,忽略返回值。

接上面的例子

// 忽略掉第一个返回值,接受第二个返回值
_, y := split(17)

// 接受第一个返回值,忽略第二个返回值
x, _ := split(17)

4. defer语句

defer是延迟调用语句,延迟调用指的是被defer修饰的函数调用,在父函数执行接结束的时候才会执行defer修饰的函数。

4.1. 基本用法

例子:

package main

import "fmt"

func main() { // 父函数
   // 延迟调用Println函数,也就是延迟打印world字符串
   defer fmt.Println("world")
   
   // 打印hello
   fmt.Println("hello")
}

执行代码输出:helloworld

执行流程说明:

使用defer修饰fmt.Println("world"),并不会立即执行Println函数,所以不会打印world。

fmt.Println("hello")语句会立即执行,输出hello

这个时候main函数执行结束,因为main函数是父函数,这个时候会执行 defer fmt.Println("world") 函数,输出world。

说明:父函数是一个相对概念,调用函数的函数,就是父函数。

4.2. defer调用栈

如果在同一个函数中,存在多个defer修饰的延迟调用函数,那么执行顺序是怎么样的?

例子:

package main

import "fmt"

func main() {
    fmt.Println("counting")

    for i := 0; i < 10; i++ {
        // 延迟打印 i
	defer fmt.Println(i)
    }
    
    // 会比上面的defer语句先执行
    fmt.Println("done")
}

执行后输出:

counting
done
9
8
7
6
5
4
3
2
1
0

执行流程,延迟调用函数,会保存在一个调用栈中,执行的时候反序执行,所以看到上面例子,数字倒序输出。

5.闭包(匿名函数)

没有函数名的函数,我们叫做匿名函数,通常也叫做闭包,它拥有可以引用定义闭包上下文环境变量的特性。

简单的闭包例子:

// 定义一个闭包,并将闭包函数赋值给变量f
f := func() {
        fmt.Println("我是闭包函数")
    }
    
// 通过变量f调用闭包函数
f();

闭包引用上下文环境变量的例子:

package main

import (
    "fmt"
)

func main() {
    // 计数器变量
    count := 0

    // 定义一个闭包,并将闭包函数赋值给变量f
    f := func() {
        // 因为闭包函数是在main函数中定义的,所以可以引用main函数定义的变量
        count++
        fmt.Println("count=", count)
    }

    // 通过变量f调用闭包函数
    f();
    f();
    f();
}

输出:

count= 1
count= 2
count= 3

上下文环境,指的就是定义闭包函数的函数内的局部作用域。