• 无需声明原型。
• 支持不定 变参。
• 支持多返回值。
• 支持命名返回参数。
• 支持匿名函数和闭包。
• 函数也是一种类型,一个函数可以赋值给变量。
• 不支持 嵌套 (nested) 一个包不能有两个名字一样的函数。
• 不支持 重载 (overload)
• 不支持 默认参数 (default parameter)。
在默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。
注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
注意2:map、slice、chan、指针、interface默认以引用的方式传递。
不定参数不定参数传值 就是函数的参数不是固定的,后面的类型是固定的。(可变参数)
Golang 可变参数本质上就是 slice。只能有一个,且必须是最后一个。
在参数赋值时可以不用用一个一个的赋值,可以直接传递一个数组或者切片,特别注意的是在参数后加上“…”即可。
func myfunc(args ...int) { //0个或多个参数
}
func add(a int, args…int) int { //1个或多个参数
}
func add(a int, b int, args…int) int { //2个或多个参数
}
注意:其中args是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数.
闭包、递归
闭包是由函数及其相关引用环境组合而成的实体(即:闭包=函数+引用环境)。
func test() func() {
x := 100
fmt.Printf("x (%p) = %d\n", &x, x)
return func() {
fmt.Printf("x (%p) = %d\n", &x, x)
}
}
func main() {
test()()
}
在汇编层 ,test 实际返回的是 FuncVal 对象,其中包含了匿名函数地址、闭包对象指针。当调 匿名函数时,只需以某个寄存器传递该对象即可。
外部引用函数参数局部变量func add(base int) func(int) int {
return func(i int) int {
base += i
return base
}
}
func main() {
tmp1 := add(10)
// 0x7cbda0 func(int) int
fmt.Printf("%v %T \n",tmp1,tmp1)
fmt.Println(tmp1(1))
fmt.Printf("%v %T \n",tmp1,tmp1)
fmt.Println(tmp1(2))
tmp2 := add(100)
fmt.Printf("%v %T \n",tmp1,tmp1)
fmt.Println(tmp2(1))
fmt.Printf("%v %T \n",tmp1,tmp1)
fmt.Println(tmp2(2))
}
------------------------------------
// base一直存在,不断被修改
0x10bbf20 func(int) int
11
0x10bbf20 func(int) int
13
0x10bbf20 func(int) int
101
0x10bbf20 func(int) int
103
延迟调用(defer)
defer 是先进后出
这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法执行了。
defer 碰上闭包func main() {
var whatever [5]struct{}
for i := range whatever {
defer func() { fmt.Println(i) }()
}
}
------------------------------
4
4
4
4
4
Each time a “defer” statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked.
也就是说函数正常执行,由于闭包用到的变量 i 在执行的时候已经变成4,所以输出全都是4.
defer后面的语句在执行的时候,函数调用的参数会被保存起来,但是不执行。也就是复制了一份。
多个defer多个 defer 注册,按 FILO 次序执行 ( 先进后出 )。哪怕函数或某个延迟调用发生错误,这些调用依旧会被执行。
package main
func test(x int) {
defer println("a")
defer println("b")
defer func() {
println(100 / x) // div0 异常未被捕获,逐步往外传递,最终终止进程。
}()
defer println("c")
}
func main() {
test(0)
}
-----------------------------------------
c
b
a
panic: runtime error: integer divide by zero
defer和return
go的return语句不是原子性的
func foo() (i int) {
i = 0
defer func() {
fmt.Println(i)
}()
return 2
}
func main() {
foo()
}
-----------------------------------
2
return 2
相当于 i = 2执行defer语句 fmt.Println(i)
return i
defer nil 函数
func test() {
var run func() = nil
// 相当于 nil()
defer run()
fmt.Println("runs")
}
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
test()
}
-------------------------------------
runs
runtime error: invalid memory address or nil pointer dereference
名为 test 的函数一直运行至结束,然后 defer 函数会被执行且会因为值为 nil 而产生 panic 异常
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)