函数的定义
1 2 3 4 5 6 7 8
| func 函数名(参数)(返回值){ 函数体 }
|
函数的参数和返回值都是可选的
函数的调用
通过函数名()的方式调用函数。
1 2 3 4 5 6 7 8 9 10 11
| package main
import "fmt"
func sum(){ fmt.Println("Hello!") }
func main(){ sum() }
|
类型简写
可变【不定长】参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package main
import "fmt"
func intSum2(x ...int) int { fmt.Println(x) sum := 0 for _, v := range x { sum = sum + v } return sum }
func main(){ ret1 := intSum2() ret2 := intSum2(10) ret3 := intSum2(10, 20) ret4 := intSum2(10, 20, 30) fmt.Println(ret1, ret2, ret3, ret4) }
|
定长参数搭配可变参数使用时,可变参数要写在最后面
1
| func intSum3(x int, y ...int) int {
|
返回值
Go通过关键字return向外输出返回值
1 2 3 4 5
| func calc(x, y int) (int, int) { sum := x + y sub := x - y return sum, sub }
|
返回值命名
1 2 3 4 5
| func calc(x, y int) (sum, sub int) { sum = x + y sub = x - y return }
|
返回值补充
当我们的一个函数返回值类型为slice时,nil可以看做是一个有效的slice,没必要显示返回一个长度为0的切片。
1 2 3 4 5
| func someFunc(x string) []int { if x == "" { return nil } }
|
全局变量和局部变量
全局变量是定义在函数外的变量,作用域是整个代码块。局部变量是定义在函数内的变量,作用域是单个函数。如果局部变量和全局变量重名,优先访问局部变量。for循环语句中定义的变量,也是只在for语句块中生效:
自定义函数类型
使用type关键字来定义一个函数类型:
1 2 3 4 5 6 7 8 9 10
| type calculation func(int, int) int
func add(x, y int) int { return x + y }
var c calculation c = add
|
函数作为参数
1 2 3 4 5 6 7 8 9 10
| func add(x, y int) int { return x + y } func calc(x, y int, op func(int, int) int) int { return op(x, y) } func main() { ret2 := calc(10, 20, add) fmt.Println(ret2) }
|
匿名函数
Go语言中函数内部不能再像之前那样定义函数,定义格式:
没有函数名,就不能通过函数名调用,匿名函数需要保存到某个变量或者作为立即执行函数:
1 2 3 4 5 6 7 8 9 10 11 12 13
| func main() { add := func(x, y int) { fmt.Println(x + y) } add(10, 20)
func(x, y int) { fmt.Println(x + y) }(10, 20) }
|
回调函数
在编写应用程序时,库函数负责提供某些封装好的功能,我们会会经常调用这些库函数,而有的库函数在被调用时需要应用程序先传递给它一个函数,在以便在合适时调用,这个被传入后又被调用的函数就称为回调函数;而把回调函数传入库的动作被称为回调函数登记。
回调函数的三方
中间函数【接受回调函数的函数】,回调函数,起始函数【即主函数】
阻塞式回调:回调函数的调用发生在起始函数返回值之前;
延迟式回调:回调函数的调用发生在起始函数返回值之后。
1 2 3 4 5 6 7 8 9 10
| func a() func() { return func() { fmt.Println("this is ", name) } }
func main() { res := a() res() }
|
闭包
闭包组成要素:
#函数 + #外层变量的引用
1 2 3 4 5 6 7 8 9 10 11
| func a() func() { name := "Daqian" return func() { fmt.Println("this is ", name) } }
func main() { res := a() res() }
|
定义进化:
1 2 3 4 5 6 7 8 9 10
| func a(name string) func() { return func() { fmt.Println("this is ", name) } }
func main() { res := a("Xi Gua") res() }
|
定义进化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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")) }
|
延迟处理语句
defer:会将跟在其后面的语句进行延迟处理。多个defer语句会按逆顺序执行,即后被defer的语句先执行
1 2 3 4 5 6 7 8 9 10
| package main
import "fmt"
func main() { x := 1 defer fmt.Println(x) x = 10 defer fmt.Println(x) }
|
defer在return中的执行顺序
1 2 3 4 5 6 7 8 9 10 11 12 13
| return x 1 - 返回值 = x 2 - return 返回值
func f2()(x int){ defer func{ x++ }() return 5 } 1 -
|
常用函数
close:主要用于关闭channel
len:用来求长度
new:用来分配内存,针对值类型,比如int、struct,返回值是指针
make:用来分配内存,针对引用类型,比如chan、map、slice
append:追加元素到数组、slice中
panic和recover:错误处理
panic / recover:
panic的作用是引发异常,从而使程序停止执行。它可以在任何地方引发异常。
recover的作用是恢复panic引发的异常,使程序继续正常执行。recover只能在defer语句中使用,而defer语句则在可能引发panic之前定义。
闭包的特性:
- 闭包通常以函数的形式定义,它的返回值是一个匿名函数
- 内存逃逸;可以通过闭包的返回值访问并操作闭包内匿名函数引用的外部局部变量
1 2 3 4 5 6 7 8
| func add() func() int { sum := 0 return func() int { sum += 1 return sum }
}
|