Go-函数
这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
这也是我学习Go的第四天
什么是函数
- 函数是基本的代码块,用于执行一个任务
- Go语言最少有个main函数
- 通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。
- 函数声明告诉了编译器函数的名称,返回类型,和参数。
函数的声明
Go 语言函数定义格式如下:
func function_name([parameter list])[return_types]{
函数体
}
- 无参无返回值
- 有一个参数
- 有两个参数的函数
- 有一个返回值的函数
- 有多个返回值的函数
// 无参无返回值
func printinfo() {
fmt.Println("printinfo")
}
// 有一个参数
func myprint(msg string) {
println(msg)
}
// 有两个参数的函数
// 返回值
func add(a, b int) int {
println(a + b)
return a + b
}
//有多个返回值的函数
func addxy(a, b int)( int,int) {
println(a + b)
return a,b
}
可变参数
概念:一个函数的参数类型确定,但个数不确定,就可以使用可变参数
// 可变参数
func myfunc(arg ...int) {
// arg ...int告诉go这个函数接收不定数量的参数,类型全是int
}
// main 主函数
func main() {
getSum("123", 2, 3, 4, 5, 6)
}
// ...可变参数
func getSum(msg string,nums ...int) {
sum := 0
for i := 0; i < len(nums); i++ {
fmt.Println(nums[i])
//sum = sum+num[i]
sum += nums[i]
}
fmt.Println("sum :", sum)
}
参数传递
按照数据的存储特点来分:
- 值类型的数据:操作的是数据本身、int、string、bool、float64、array...
- 引用类型的数据: 操作的是数据的地址 slice、map、chan...
值传递:传递的是数据的副本,修改数据,对于原始的数据没有影响
import "fmt"
func main() {
//值传递
// 定义一个数组 【个数】类型
arr := [4]int{1, 2, 3, 4}
fmt.Println(arr)
// 传递: 拷贝arr
update(arr)
fmt.Println("调用更新后的数据:", arr)
//引用传递
}
func update(arr2 [4]int) {
fmt.Println("arr2接收的数据", arr2)
arr2[0] = 100
fmt.Println("arr2修改的数据", arr2)
}
引用传递:slice 引用传递,变量在内存中是存放在一定的地址上的,修改变量实际是修改变量地址处的内存。
func main() {
//切片,可以扩容的数组
s1 := []int{1, 3, 2, 4}
fmt.Println("传递的数据", s1)
update2(s1)
fmt.Println("调用更新的数据:", s1)
}
func update2(s2 []int) {
fmt.Println("传递的数据", s2)
s2[0] = 100
fmt.Println("更新的数据", s2)
}
defer 延迟函数执行
defer语义:推迟、延迟 在go语言中,使用defer关键字来延迟一个函数或者方法的执行
func main() {
f("1")
f("2")
defer f("3") // 延迟执行
f("4")
}
func f(s string) {
fmt.Println(s)
}
defer函数或者方法:一个函数或方法的执行被延迟了
- 你可以在函数中添加多个defer语句,当函数被执行到最后,这些defer语句会按照逆序执行,最后该函数返回,特别是当你进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄漏等问题
- 如果有很多调用defer,那么defer是采用后进先出(栈)模式
func main() {
f("1")
f("2")
defer f("3") // 延迟执行
f("4")
defer f("8") // 延迟执行
defer f("6") // 延迟执行
}
func f(s string) {
fmt.Println(s)
}
函数高级
函数的数据类型
import "fmt"
// func 本身也是一个数据类型
func main() {
fmt.Printf("%T", f1)
}
func f1() {
}
匿名函数推导
func main() {
f1()
f2 := f1 //函数本身也是一个变量
//赋值
f2()
// 匿名函数
f3 := func() {
fmt.Println("我是f3函数")
}
f3()
// 省略写法
func(a, b int) int {
fmt.Println("我是f5函数")
return a + b
}(1, 2)
}
func f1() {
}
回调函数
函数可以作为参数传递。
高阶函数:根据go语言的数据类型的特点,可以将一个函数作为另外一个函数的参数。fun1() ,fun2() 将fun1函数作为fun2这个函数的参数 fun2函数:就叫做高阶函数,接收了一个函数作为参数的函数 fun1函数:就叫做回调函数,作为另外一个函数的参数
import "fmt"
func main() {
r1 := add(1, 2)
fmt.Println(r1)
// add 为回调函数
// add 作为参数
r2 := oper(3, 4, add)
fmt.Println(r2)
// 匿名函数
r4 := oper(8, 4, func(a int, b int) int {
if b == 0 {
fmt.Println("00000")
return 0
}
return a / b
})
println(r4)
}
// 高阶函数
func oper(a, b int, f func(int, int) int) int {
r := f(a, b)
return r
}
func add(a, b int) int {
return a + b
}
闭包
import "fmt"
func main() {
r1 := increment()
println(r1)
v1 := r1()
println(v1)
v2 := r1()
fmt.Println(v2)
fmt.Println(r1())
fmt.Println(r1())
fmt.Println(r1())
//
r2 := increment()
v3 := r2()
println(v3)
fmt.Println(r1())
fmt.Println(r2())
}
// 自增
func increment() func() int {
//局部变量 i
i := 0
//定义一个匿名函数,给变量自增并返回
fun := func() int { // 内层函数,害没有执行的
i++
return i
}
return fun
}