函数
- 函数的声明:
- go没有默认参数的说法
- 函数都是传值的方式,即传递的是一份拷贝。对于大部分变量来说,形参的修改不会影响实参的值。但是,切片(slice)、map、channel等引用类型(更准确的说法是:这三个类型都是结构体含指针的方式,指针的拷贝指向的是同一个存储空间),则修改形参的值会改变原实参的内容。其他的类型的变量都要传递指针类型,才会改变原实参的内容(是改变指向内容的值,而不是改变传入的参数,传入的参数还是一份拷贝)。
/*
paramter-list:参数列表
return-list:返回值列表,go可以返回多个值(c++只能返回一个)。
如果没有返回值,则可以不写(c++没有返回值也要用void)。
*/
func funcName(paramter-list) (return-list){
body;
}
func Marshal(v any) ([]byte, error) {
...
return buf, nil
}
//如果返回值有名称,该变量也认为是在函数内的局部变量,return后可不跟。
func Marshal(v any) (buf []byte, err error) {
...
return
}
- 可变参数
在声明可变参数的函数时,可变参数类型在参数列表的最后,通过(param …Type)的方式在声明可变参数类型。可变参数可以理解为切片,因此也可以直接将切片变量传给函数,但是不能将数组传进去。
arr := []int{2, 1}
arr1 := [...]int{2, 1}
totalA := firstChapter.Sum1(arr...) //注意后面一定要带...
//报错,无法将“Cannot use 'arr1' (type [2]int) as the type []int”,
//看出可变参数列表其实就是一个切片
totalB := firstChapter.Sum1(arr1...)
total := firstChapter.Sum(str1, 2, 3, 4, 5)
func Sum(str string, args ...int) int {
var total int = 0
for _, vals := range args {
total += vals
}
return total
}
func Sum1(args ...int) int {
var total int = 0
for _, vals := range args {
total += vals
}
return total
}
- 匿名函数和闭包
匿名函数:和正常的函数相比,少了函数名。它是一个函数值,不能够单独存在,但是可以赋值给某个变量,或者当作一个函数的返回值(即保存函数的地址给变量),然后通过变量名对函数进行调用。
闭包:匿名函数也称作为闭包, 可以访问它们所在外部函数内的所有局部变量、参数等。这些被访问的变量的生命周期不是其作用域,而是直到闭包不在被调用了,才会销毁。
//匿名函数赋值给变量
z := func(x int, y int) int { return x + y }
num := z(2, 3) //5
func Square() func() int {
var x = 0
logrus.Info("inti")
return func() int {
//x的生命周期不是由其作用域决定,匿名函数调用期间,x一直有效
x++
logrus.Info(x)
return x
}
f := firstChapter.Square()
logrus.Info(f()) //1
logrus.Info(f()) //2
logrus.Info(f() //3
x是在Square函数中声明的,但是在闭包没有结束之前,x的值一直有效。可以理解为:闭包中使用变量,相当于引用传递,而非值传递。对于闭包中使用的变量,无论闭包何时被调用,闭包都可以使用这些变量,而不用考虑这些变量的作用域。
闭包常用的场景:待续…