函数

教程地址:点击去往视频教程open in new window

1. 函数定义

func function_name( [parameter list] ) [return_types] {
   函数体
}
1
2
3
  • func:函数由 func 开始声明
  • function_name:函数名称,函数名和参数列表一起构成了函数签名。
  • parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
  • 函数体:函数定义的代码集合。

示例:

package main

import "fmt"

func main() {
	fmt.Println(max(1, 10))
	fmt.Println(max(-1, -2))
}
//类型相同的相邻参数,参数类型可合并。
func max(n1, n2 int) int {
	if n1 > n2 {
		return n1
	}
	return n2
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//在定义函数时 x,y这两个参数,称之为形参
func swap(x, y int) (int, int) {
	return y, x
}

1
2
3
4
5
func main() {
	var a = 10
	var b = 20
    //在调用函数时,传递的a,b两个参数,称之为实参
	swap(a, b)
}
1
2
3
4
5
6

2. 函数的使用

Go中的函数比较特殊,被誉为一等公民,其本身可以当做一个数据类型

比如:

func main() {
	var swap func(x, y int) (int, int)
	swap = func(x, y int) (int, int) {
		return y, x
	}
	fmt.Println(swap(10, 20))
}
1
2
3
4
5
6
7

函数既然可以做为一个变量,那么其可以做为参数传递和做为返回值

比如:

func main() {
	var swap func(x, y int) (int, int)
	swap = func(x, y int) (int, int) {
		return y, x
	}
	r := call(swap)
	r(10)
}

func call(swap func(x, y int) (int, int)) func(x int) {
	y, _ := swap(10, 20)
	return func(x int) {
		fmt.Println(y + x)
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

我们可以看出,在Go语言中,函数是比较灵活的,这种灵活可以让Go做到真正的函数式编程,并且在Go语言编程中被广泛应用

3. 参数和返回值

  • 参数可以不传,参数也可以传递多个,也可以参数数量不固定

    // 不传参数
    func noParams() (int, int) {
    	return 10, 20
    }
    
    // 传多个参数
    func swap(x, y int) (int, int) {
    	return y, x
    }
    // 不固定参数 只能写在最后
    func unfixedParams(y int, x ...int) (int, int) {
    	return x[0], x[1]
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • Go语言中参数传递为值传递,函数接收参数时,是接收的一个副本,实参copy了一份给形参

    func main() {
    	var a = 10
    	var b = 20
    	changeValue(a, b)
    	fmt.Println("不影响:", a, b)
    	changeValuePoint(&a, &b)
    	fmt.Println("影响:", a, b)
    }
    // 在函数中修改值 不会影响 a和b
    func changeValue(x, y int) {
    	x = 50
    	y = 100
    }
    // 虽然是值传递 由于传递的是地址 所以修改值 会影响a和b
    func changeValuePoint(x, y *int) {
    	*x = 50
    	*y = 100
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    指针类型在参数传递过程中,只占用4字节(32位系统)或8字节(64位系统)的大小,内存开销小

问题:指针参数一定更节省内存吗? 答案 :不一定

  • 返回值可以没有,可以是一个,也可以是多个

    // 无返回值
    func no(x, y int) {
    }
    
    // 多返回值
    func yes(x, y int) (int, int, string) {
    	return x, y, ""
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
  • 命名返回值

    // 命名返回值 相当于局部变量 return隐式返回
    func yes(x, y int) (a int, b int, info string) {
    	a = 10
    	b = 20
    	info = "hello"
    	return
    }
    
    1
    2
    3
    4
    5
    6
    7

4. 匿名函数

匿名函数就是没有函数名的函数。

比如:

func main() {
	//这是一个匿名函数
	funA := func() int {
		return 20
	}
	//其实在这里funA就是函数的名字
	funA()
	//这是一个匿名函数调用 可以不用将函数声明为一个变量在使用
	func() {
		fmt.Println("这是一个匿名函数")
	}()
}

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

5. 闭包

所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

闭包=函数+引用环境,这里可以简单的理解为闭包是函数内部的匿名函数

func main() {
	// 创建一个玩家生成器
	generator := playerGen("码神")
	// 返回玩家的名字和血量
	name, hp := generator()
	// 打印值
	fmt.Println(name, hp)
}

// 创建一个玩家生成器, 输入名称, 输出生成器
func playerGen(name string) func() (string, int) {
	// 血量一直为150
	hp := 150
	// 返回创建的闭包
	return func() (string, int) {
		// 将变量引用到闭包中
		return name, hp
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19