go语言笔记—函数

函数是组织好的、可重复使用的、用来实现单一或相关联功能的代码段,其可以提高应用的模块性和代码的重复利用率。Go 语言支持普通函数、匿名函数和闭包,从设计上对函数进行了优化和改进,让函数使用起来更加方便。Go 语言的函数属于“一等公民”(first-class),也就是说:

  • 函数本身可以作为值进行传递。
  • 支持匿名函数和闭包(closure)。
  • 函数可以满足接口。

函数定义

格式:

func 函数名(形式参数列表)(返回值列表){
    函数体
}

多返回值:

func typedTwoValues() (int, int) {
    return 1, 2
}

对返回值命名:

func namedRetValues() (a, b int) {
    a = 3
    b = 2
    return
}

函数作为变量:

func fire()  {
    fmt.Println("fire")
}
func main() {
    var f func()
    f = fire
    f()

}

匿名函数:

匿名函数的定义就是没有名字的普通函数定义

定义格式:

func(参数列表)(返回参数列表){
    函数体
}

可变参数:

func myfunc(args ...int) {
    for _, arg := range args {
        fmt.Println(arg)
    }
}

defer延迟执行语句

Go语言的 defer 语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。关键字 defer 的用法类似于面向对象编程语言 Java和 c# 的 finally 语句块,它一般用于释放某些已分配的资源,典型的例子就是对一个互斥解锁,或者关闭一个文件。

func main() {
    fmt.Println("defer begin")
    // 将defer放入延迟调用栈
    defer fmt.Println(1)
    defer fmt.Println(2)
    // 最后一个放入, 位于栈顶, 最先调用
    defer fmt.Println(3)
    fmt.Println("defer end")
}

递归

斐波拉且:

func Fibonacci(n uint64) (result uint64) {
    if n == 1 || n==2 {
        return 1
    }
    return Factorial(n-1) + Factorial(n-2)
}

阶乘:

func Factorial(n int64) (rs int64)  {
    if n == 1 {
        return 1
    }
    return n*Factorial(n-1)
}

go语言测试

规则:

要开始一个单元测试,需要准备一个 go 源码文件,在命名文件时文件名必须以_test.go结尾,单元测试源码文件可以由多个测试用例(可以理解为函数)组成,每个测试用例的名称需要以 Test 为前缀,例如:

func TestXxx( t *testing.T ){
    //......
}

编写测试用例有以下几点需要注意:

  • 测试用例文件不会参与正常源码的编译,不会被包含到可执行文件中;
  • 测试用例的文件名必须以_test.go结尾;
  • 需要使用 import 导入 testing 包;
  • 测试函数的名称要以TestBenchmark开头,后面可以跟任意字母组成的字符串,但第一个字母必须大写,例如 TestAbc(),一个测试用例文件中可以包含多个测试函数;
  • 单元测试则以(t *testing.T)作为参数,性能测试以(t *testing.B)做为参数;
  • 测试用例文件使用go test命令来执行,源码中不需要 main() 函数作为入口,所有以_test.go结尾的源码文件内以Test开头的函数都会自动执行。

Go语言的 testing 包提供了三种测试方式,分别是单元(功能)测试、性能(压力)测试和覆盖率测试。

单元测试

在同一文件夹下创建两个Go语言文件,分别命名为 demo.go 和 demt_test.go

demo.go:

// 根据长宽获取面积
func GetArea(weight int, height int) int {
    return weight * height
}

demo_test.go:

import "testing"
func TestGetArea(t *testing.T) {
    area := GetArea(40, 50)
    if area != 2000 {
        t.Error("测试失败")
    }
}

测试运行:go test -v

压力测试

demo_test.go:

import "testing"
func BenchmarkGetArea(t *testing.B) {
    for i := 0; i<t.N; i++{
        GetArea(40,50)
    }
}

测试运行:go test -bench="."

覆盖率测试

demo_test.go:

import "testing"

func TestGetArea(t *testing.T) {
    area := GetArea(40, 50)
    if area != 2000 {
        t.Error("测试失败")
    }
}
func BenchmarkGetArea(t *testing.B) {
    for i := 0; i < t.N; i++ {
        GetArea(40, 50)
    }
}

测试运行:go test -cover