Go 语言函数
1. 概述
函数是基本的代码块,用于执行一个任务
Go 语言最少有一个 main() 函数
你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务
函数声明告诉了编译器函数的名称,返回类型,和参数
Go 语言标准库提供了多种可动用的内置的函数。
例如,len()函数可以接受不同类型参数并返回该类型的长度。如果我们传入的是字符串则返回字符串的长度,如果传入的是数组,则返回数组中包含的元素个数。
2. 函数的定义
Go 语言函数定义格式如下:
func 函数名 (参数列表) (返回值列表)
无参数返回值
func test() {}
传参有返回值
func test(a int,b int) int {return n}
传参有多个返回值
func result(a int,b int)(int,int) {return a+b,a*b}
- 示例: 定义max()函数传入两个整形参数 num1 和 num2,并返回这两个参数的最大值
/* 函数返回两个数的最大值 */func max(num1, num2 int) int {/* 声明局部变量 */var result intif num1 > num2 {result = num1} else {result = num2}return result}
3. 函数调用
- 当创建函数时,你定义了函数需要做什么,通过调用该函数来执行指定任务,调用函数,向函数传递参数,并返回值
函数的调用
package mainimport \"fmt\"func main() {var (a int = 100b int = 200)var result int//函数调用,注意返回值和接受值类型必须一致result = max(a, b)fmt.Println(\"最大值为:\", result)}/* 函数返回两个数的最大值 */func max(num1, num2 int) int {/* 声明局部变量 */var result intif num1 > num2 {result = num1} else {result = num2}return result}//输出结果如下最大值为: 200
函数返回多个值
package mainimport \"fmt\"func swap(x, y string) (string, string) {return y, x}func main() {a, b := swap(\"hello\", \"world\")fmt.Println(a, b)}//输出结果如下world hello
package mainimport \"fmt\"func main() {var (a, b = multi_value(3, 5))fmt.Println(\"和:\", a, \"\\n积:\", b)}func multi_value(num1, num2 int) (int, int) {result1 := num1 + num2result2 := num1 * num2//返回两数和,两数乘积return result1, result2}//输出结果如下和: 8积: 15
4. 函数参数
- 函数如果使用参数,该变量可称为函数的
形参
- 形参就像定义在函数体内的局部变量
- 调用函数,可以通过两种方式来传递参数
默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数
传递类型 | 描述 |
---|---|
值传递 | 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数 |
引用传递 |
引用传递是指在调用函数时将实际参数的 地址 传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数 |
值类型
package mainimport \"fmt\"func main() {var (num1 = 10num2 = 20)fmt.Println(\"交换前\\n\")fmt.Printf(\"num1: %v\\n\", num1)fmt.Printf(\"num2: %v\\n\", num2)swap(num1, num2)fmt.Println(\"\\n交换后\\n\")fmt.Printf(\"num1: %v\\n\", num1)fmt.Printf(\"num2: %v\\n\", num2)}//两数交换func swap(a, b int) {a, b = b, a}//输出结果如下交换前num1: 10num2: 20交换后num1: 10num2: 20
总结:
可以看到,实际的值并没有交换,只是把实际参数给复制了一份传递到了函数中去,并不会影响原本的实际参数
引用类型
package mainimport \"fmt\"func main() {var (num1 = 11num2 = 22)fmt.Println(\"交换前\")fmt.Printf(\"num1: %v, num2: %v\\n\", num1, num2)fmt.Println(\"-----------------\")swap(&num1, &num2)fmt.Println(\"交换后\")fmt.Printf(\"num1: %v, num2: %v\\n\", num1, num2)}//引用类型交换func swap(a, b *int) {*a, *b = *b, *a}//输出结果如下交换前num1: 11, num2: 22-----------------交换后num1: 22, num2: 11
5. 函数作为实参
-
可以很灵活的创建函数,并作为另一个函数的实参
-
示例:
使用
math
数学包
package mainimport (\"fmt\"\"math\")func main() {//函数变量result := func(x float64) float64 {return math.Sqrt(x)}fmt.Println(result(9))fmt.Println(\"-10的绝对值:\", math.Abs(-10))fmt.Println(\"5.2向下取整:\", math.Ceil(5.2))fmt.Println(\"5.8向下取整:\", math.Floor(5.8))fmt.Println(\"11除3的余数:\", math.Mod(11, 3))fmt.Println(\"取整数,取小数\")fmt.Println(math.Modf(5.26))fmt.Println(\"3的2次方\", math.Pow(3, 2))fmt.Println(\"10的4次方\", math.Pow10(4))fmt.Println(\"8的开平方\", math.Sqrt(8))fmt.Println(\"8的开立方\", math.Cbrt(8))fmt.Println(\"圆周率\", math.Pi)}//输出结果如下3-10的绝对值: 105.2向下取整: 65.8向下取整: 511除3的余数: 2取整数,取小数5 0.25999999999999983的2次方 910的4次方 100008的开平方 2.82842712474619038的开立方 2圆周率 3.141592653589793
6. 回调函数
回调函数是一个被作为参数传递的函数,可以大大提升编程的效率。
函数执行流程描述
① 首先在main函数中调用了test1()函数,这时候test1会顺着去加载里面的语句 1、2,直到语句2加载完后,加载回调函数test2,test2会执行函数体内的语句 1、2,3;
② 当test2函数体中语句执行完成,回调函数的生命周期将结束,如果有返回值将返回,没有则结束;
③ 当回调函数执行完以后,将继续执行test1函数中的语句 3,4,执行完以后test1函数的生命周期也将结束
④ test1函数结束以后就会返回main主函数
package mainimport \"fmt\"//声明函数类型type cback func(int) intfunc main() {//对回调函数进行隐匿,能起到保护作用,并且提高程序的运行效率test_cback(1, callback)}//测试函数,用来调用回调函数func test_cback(x int, f cback) {fmt.Println(\"test_back函数:语句1\")f(x)fmt.Println(\"test_back函数:语句2\")}//回调函数func callback(a int) int {fmt.Println(\"回调函数callback:\", a)return a}//执行结果如下test_back函数:语句1回调函数callback: 1test_back函数:语句2
7. 匿名函数
- 匿名函数就是没有函数名的函数,匿名函数多用于实现回调函数和闭包
- 匿名函数是一个\”内联\”语句或表达式
- 匿名函数的优越性在于可以直接使用函数内的变量,不必申明
- 匿名函数的定义格式如下:
func(参数)(返回值){函数体}
匿名函数的执行方式如下
- ① 把匿名函数赋值给变量
package mainimport \"fmt\"func main() {sayHello := func() {fmt.Println(\"匿名函数\")}sayHello()}//执行结果如下匿名函数
- ② 立即执行函数
package mainimport \"fmt\"func main() {func() {fmt.Println(\"匿名函数\")}() //匿名函数定义完成加上()可以直接进行执行}//执行结果如下匿名函数
8. 闭包
- 闭包可以理解为
定义在一个函数内部的函数
,本质上闭包是将函数内部和外部连接起来的桥梁,或者说是函数和其引用环境的组合体
- 闭包指的是一个函数和与其相关的引用环境组合而成的实体。简单来说,
闭包=函数+引用环境
闭包示例 ①
package mainimport \"fmt\"//定义一个函数,他的返回值是一个函数//把函数作为返回值func a() func() {name := \"world\"return func() {fmt.Println(\"hello\", name) //先在函数内找name变量,找不到就上函数体外层去找}}func main() {//闭包 = 函数+外出变量的引用r := a() //r就是一个闭包r() //相当于执行了a函数的匿名函数}//执行结果hello world
示例 ②
package mainimport (\"fmt\"\"strings\")//使用闭包做文件后缀名检测func makeSuffixFunc(suffix string) func(string) string {return func(name string) string {if !strings.HasSuffix(name, suffix) {//判断字符串后缀的格式return name + suffix}return name}}func main() {jpgFunc := makeSuffixFunc(\".jpg\")txtFunc := makeSuffixFunc(\".txt\")fmt.Println(jpgFunc(\"test\"))fmt.Println(txtFunc(\"test\"))}//执行结果如下test.jpgtest.txt
示例 ③
package mainimport \"fmt\"func calc(base int) (func(int) int, func(int) int) {add := func(i int) int {base += ireturn base}sub := func(i int) int {base -= ireturn base}return add, sub}func main() {x, y := calc(100)ret1 := x(200)//调用x的时候传入值为200;base = 100 + 200fmt.Printf(\"ret1: %v\\n\", ret1)ret2 := y(200)//base = 300 - 200fmt.Printf(\"ret2: %v\\n\", ret2)}//输出结果如下ret1: 300ret2: 100
- 示例 ④
//回调函数是把函数作为传递参数,而闭包则是把函数作为一个返回值package mainimport \"fmt\"func close_package() func() int {i := 0return func() int {i += 1return i}}func main() {//定义函数 使用闭包做+1操作nextNumber := close_package()fmt.Println(\"使用nextNumber做自增\")fmt.Println(nextNumber())fmt.Println(nextNumber())fmt.Println(nextNumber())fmt.Println(\"使用nextNumber1做自增\")nextNumber1 := close_package()fmt.Println(nextNumber1())fmt.Println(nextNumber1())fmt.Println(nextNumber1())}//执行结果如下使用nextNumber做自增123使用nextNumber1做自增123