1. 函数定义
1.1 golang函数特点
• 无需声明原型。
• 支持不定 变参。
• 支持多返回值。
• 支持命名返回参数。
• 支持匿名函数和闭包。
• 函数也是一种类型,一个函数可以赋值给变量。
• 不支持 嵌套 (nested) 一个包不能有两个名字一样的函数。
• 不支持 重载 (overload)
• 不支持 默认参数 (default parameter)。
函数声明包含一个函数名,参数列表,返回列表和函数体。参数列表,返回列表可以省略。
package main
import "fmt"
func test(fn func() int) int {
return fn()
}
// 定义函数类型。
type FormatFunc func(s string, x, y int) string
func format(fn FormatFunc, s string, x, y int) string {
return fn(s, x, y)
}
func main() {
s1 := test(func() int { return 100 }) // 直接将匿名函数当参数。
s2 := format(func(s string, x, y int) string {
return fmt.Sprintf(s, x, y)
}, "%d, %d", 10, 20)
println(s1, s2)
}
2. 参数
函数定义时的参数称为函数的形参(定义在函内部使用的局部变量);
调用函数传递过来的变量称为函数的实参。实参可以通过两种方式传递:值传递和引用传递;
package main
import "fmt"
// 值传递
func valueTest(x, y int) (int, int) {
x, y = y, x
return x, y
}
// 引用传递
/*
map、slice、chan、指针、interface默认以引用的方式传递
*/
func quoteTest(x, y *int) (*int, *int) {
*x, *y = *y, *x
return x, y
}
// 不定参数传值
func manyTest(args ...int) {
}
func main() {
x := 0
y := 1
valueTest(x, y)
fmt.Println(x, y)
quoteTest(&x, &y)
fmt.Println(x, y)
}
3. 返回值
GoLang的返回值可以被命名,返回值的名称应具有一定意义,可读性强。
没有参数的return语句返回各个返回变量当前值。
4. 匿名函数
匿名函数由一个不带函数名的函数声明和函数体组成。匿名函数的优越性在于可以直接使用函数内部的变量,不必声明。
5. 闭包、递归
5.1 闭包
闭包是由函数及其相关引用环境组合而成的实体(闭包=函数+引用环境)。
// 闭包复制的是原对象指针
func a() func() int {
i := 0
b := func() int {
i++
fmt.Println(i)
return i
}
return b
}
5.2 递归
递归:程序在运行过程中调用自己,就叫做递归函数。
构成递归的两个必要条件:
1.子问题与原始问题为同样的事,且更为简单。
2.不能无限调用自身,必须有函数出口。
func factorial(i int) int {
if i <= 1 {
return 1
}
return i * factorial(i-1)
}
斐波那契数列(Fibonacci)
package main
import "fmt"
func fibonaci(i int) int {
if i == 0 {
return 0
}
if i == 1 {
return 1
}
return fibonaci(i-1) + fibonaci(i-2)
}
func main() {
var i int
for i = 0; i < 10; i++ {
fmt.Printf("%d\n", fibonaci(i))
}
}
6. 延时调用(defer)
后进先出(堆栈)
defer特性:
1. 关键字 defer 用于注册延迟调用。
2. 这些调用直到 return 前才被执。因此,可以用来做资源清理。
3. 多个defer语句,按先进后出的方式执行。
4. defer语句中的变量,在defer声明时就决定了。
defer用途:
1. 关闭文件句柄
2. 锁资源释放
3. 数据库连接释放
7. 异常处理
Golang没有结构化异常,使用panic抛出异常,recover捕获异常(一般在defer中通过recover捕获异常)。
panic:
1.内置函数
2.函数F中书写了panic语句,会终止之后要执行的代码,在panic所在函数F内如果存在要执行的defer函数列表,逆序执行
3.返回函数F的调用者G,在G中,调用函数F语句之后的代码不会执行,如果函数G中存在要执行的defer函数列表,逆序执行
4.知道goroutine整个推出,并报告错误
recover:
1.内置函数
2.用来控制一个groutine的panicking行为,捕获panic,从而影响应用的行为
3.一般建议的调用:
(1).在defer函数中,通过recover终止一个goroutine的panicking过程,从而恢复正常代码的执行
(2).通过panic传递的error
注意
1.利用recover处理panic指令,defer必须放在panic定义之前。recover只有在defer调用的函数中才有效,否则当panic时,recover无法捕获panic,无法防止panic扩散。
2.recover处理异常后,逻辑并不会恢复到panic那个点去,函数跑到defer之后的那个点
3.多个defer会形成defer栈,后定义的defer语句会最先被调用
error:
标准库 errors.New 和 fmt.Errorf 函数用于创建实现 error 接口的错误对象。通过判断错误对象实例来确定具体错误类型。
导致关键流程出现不可修复性错误的使用 panic,其他使用 error。
8. 测试
1. 单元测试
类型 | 格式 | 作用 |
---|---|---|
测试函数 | 函数名前缀为Test | 测试程序的一些逻辑行为是否正确 |
基准函数 | 函数名前缀为Benchmark | 测试函数的性能 |
示例函数 | 函数名前缀为Example | 为文档提供示例文档 |
2. 压力测试
压力测试用例必须遵循如下格式,其中XXX可以是任意字母数字的组合,但是首字母不能是小写字母
func BenchmarkXXX(b *testing.B) { ... }