Go编程基础 - 函数function

本文深入探讨了Go语言中的函数特性,包括无需声明函数原型、不定长度变量参数、多返回值、命名返回值参数、匿名函数、闭包等。并通过多个实例展示了这些特性的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数function

  • Go函数不支持嵌套、重载和默认参数

  • 但是支持以下特性

    • 无需声明函数原型(C\C++需要)
    • 不定长度变量参数
    • 多返回值
    • 命名返回值参数
    • 匿名函数
    • 闭包
  • 定义函数使用关键字func,且左大括号不能另起一行

  • 函数也可以作为一种类型使用

函数基本写法

func func01() {
	fmt.Println("package lesson file lesson/lesson09.go function func01")
}

一般的函数参数

func func02(a int, b string) {
	fmt.Println("package lesson file lesson/lesson09.go function func02")
	fmt.Println("func get value [a]:", a, " [b]:", b)
}

函数参数省略写法

func func03(a, b, c int) {
	fmt.Println("package lesson file lesson/lesson09.go function func03")
	fmt.Println("func get value [a]:", a, " [b]:", b, " [c]:", c)
}

多返回值 - 建议使用这种

func func04() (int, int, int) {
	fmt.Println("package lesson file lesson/lesson09.go function func04")
	a, b, c := 1, 2, 3
	return a, b, c
}

多返回值省略写法

func func05() (a, b, c int) {
	fmt.Println("package lesson file lesson/lesson09.go function func05")
	a, b, c = 1, 2, 3
	return
}

不定长度变量参数

func func06(a ...int) {
	fmt.Println("package lesson file lesson/lesson09.go function func06")
	fmt.Println("[a]:", a, " [a.type]:", reflect.TypeOf(a))
}

固定变量与不定长度变量参数混合使用

func func07(b string, a ...int) {
	fmt.Println("package lesson file lesson/lesson09.go function func07")
	fmt.Println("[b]:", b, " [a]:", a, " [a.type]:", reflect.TypeOf(a))
}

不定长度变量的函数,不会对外发生变更

func func08(slice ...int) {
	fmt.Println("package lesson file lesson/lesson09.go function func08")
	fmt.Println("[slice]:", slice)
	slice[0] = 3
	slice[1] = 4
	fmt.Println("[slice]:", slice)
}

定常Slice作为变量传入函数

// 定常的slice作为变量传入函数,会造成外部的slice发生变更
// 这种方式进行的拷贝是slice当中地址的拷贝,也就是说操作其中的数据直接产生影响

func func09(slice []int) {
	fmt.Println("package lesson file lesson/lesson09.go function func09")
	fmt.Println("[func09.slice]:", slice)
	slice[0] = 3
	slice[1] = 4
	fmt.Println("[func09.slice]:", slice)
}

引用类型的传递

func func10(a *int) {
	fmt.Println("package lesson file lesson/lesson09.go function func10")
	*a = 2
	fmt.Println("[a.address]:", a, "[a.value]:", *a)
}

函数名称作为变量

	fmt.Println()
	fmt.Println("test func11")
	function01 := func01
	function01()

匿名函数

	fmt.Println()
	fmt.Println("test func12")
	function02 := func() {
		fmt.Println("package lesson file lesson/lesson09.go function Anonymous Function ")
	}
	function02()

闭包

func closure(x int) func(int) int {
	fmt.Println("[&x]:", &x)
	return func(y int) int {
		fmt.Println("[&x]:", &x)
		return x + y
	}
}

闭包调用

// 闭包
	fmt.Println()
	function03 := closure(10)
	fmt.Println(function03(1))
	fmt.Println(function03(2))

defer

  • defer的执行方式类似其他预演中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行
  • 即使函数发生严重错误也会执行
  • 支持匿名函数的调用
  • 常用语资源清理、文件关闭、解锁一级记录时间等操作
  • 通过与匿名函数配合可在return之后修改函数计算结果
  • 如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则则是引用某个变量的地址

defer倒序打印

func func11(){
	fmt.Println("a")
	defer fmt.Println("b")
	defer fmt.Println("c")
}

打印输出

a
c
b

循环中使用defer

	for index:=0; index < 3;index++  {
		defer fmt.Println("[index]:",index)
	}

输出

2,1,0

循环中对函数使用defer

这里实际是闭包,在func里面的index是引用,但是由于defer是在循环的最后进行引用,

	for index := 0;index < 3;index++{
		defer func() {
			fmt.Println("[index]:",index)
		}() // 调用这个函数
	}

输出

3,3,3

panic/recover

panic/recover 可以理解为try catch

  • Go没有异常机制,但是panic/recover模式来处理错误
  • Panic可以在任何地方引发,但recover只有在defer调用的函数中有效
func defer04() {
	fmt.Println()
	fmt.Println("package lesson file lesson/lesson09.go function defer04")
	functionPrintA()
	functionPanicB()
	functionPrintC()
}

func functionPrintA() {
	fmt.Println("package lesson file lesson/lesson09.go function functionPrintA")
}

func functionPanicB() {
	// 在panic之前设置defer函数,才能够让defer被访问到
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("Recover in B")
		}
	}()
	panic("package lesson file lesson/lesson09.go panic functionPanicB")

}

func functionPrintC() {
	fmt.Println("package lesson file lesson/lesson09.go function functionPrintC")
}

程序输出

package lesson file lesson/lesson09.go function defer04
package lesson file lesson/lesson09.go function functionPrintA
Recover in B
package lesson file lesson/lesson09.go function functionPrintC

程序首先运行panic,出现故障,此时跳转到包含recover()的defer函数执行,recover捕获panic,此时panic就不继续传递.但是recover之后,程序并不会返回到panic那个点继续执行以后的动作,而是在recover这个点继续执行以后的动作,即执行上面的defer函数,输出1

课堂作业

分析以下程序输出结果

func homework() {
	fmt.Println("package lesson file lesson/lesson09.go function homework")
	var fs = [4]func(){}

	for index := 0; index < 4; index++ {
		defer fmt.Println("defer [index]:", index)
		defer func() {
			fmt.Println("defer_closure [index]:", index)
		}()

		fs[index] = func() {
			fmt.Println("closure [index]:", index)
		}
	}

	for _, f := range fs {
		f()
	}
}

输出结果

package lesson file lesson/lesson09.go function homework
closure [index]: 4
closure [index]: 4
closure [index]: 4
closure [index]: 4
defer_closure [index]: 4
defer [index]: 3
defer_closure [index]: 4
defer [index]: 2
defer_closure [index]: 4
defer [index]: 1
defer_closure [index]: 4
defer [index]: 0

转载于:https://my.oschina.net/hava/blog/1552169

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值