Go语言函数 | 青训营笔记

96 阅读3分钟

函数定义

func function_name( [parameter list] ) [return_types] {
    函数体
}
  • func:关键词
  • function_name:函数名称,遵循驼峰命名法,首字母若小写则只可本包内调用,若大写则可以在其他包内调用。
  • parameter list:参数列表,参数个数不限。
  • return_types:返回类型

函数参数

值传递

值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。 假如我们定义一个函数用于交换两个变量的值

func changeNum(a int,b int){
    var t int = 0
    t = a
    a = b
    b = t
}
func main(){
    a := 1
    b := 2
    fmt.Printf("交换前:a = %v , b = %v.",a,b)  //  交换前:a = 1 , b = 2.
    changeNum(a,b)
    fmt.Printf("交换后:a = %v , b = %v.",a,b)  //  交换后:a = 1 , b = 2.
}

引用传递

引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 同样是交换两个变量的例子,假如我们使用引用传递的话,在主函数中测试变量的值就会发生改变

func changeNum(a *int,b *int){
   var temp int
   temp = *a    
   *a = *b      
   *b = temp    
}
func main(){
    a := 1
    b := 2
    fmt.Printf("交换前:a = %v , b = %v.",a,b)  //  交换前:a = 1 , b = 2.
    changeNum(&a,&b)    // 调用函数,传入的是a,b两个值的地址
    fmt.Printf("交换后:a = %v , b = %v.",a,b)  //  交换后:a = 2 , b = 1.
}

init 函数

init 函数是初始化函数,可以用来进行一些初始化操作,每一个源文件都可以包含一个 init 函数,该函数会在 main 函数之前执行。

func init(){
    fmt.Println("init函数被调用了")
}
func main(){
    fmt.Println("main函数被调用了")
}

执行以上代码,结果是:

init函数被调用了
main函数被调用了

匿名函数

定义

匿名函数是指不需要定义函数名的一种函数实现方式,匿名函数没有函数名只有函数体,由一个不带函数名的函数声明和函数体组成。

使用

  1. 在定义时调用匿名函数
func(num int){
    fmt.Printf("num = %v",num)
}(10)
  1. 将匿名函数的值返回给变量
fn := func(num int){
    fmt.Printf("num = %v",num)
}
fn(10)

闭包

定义

闭包是引用了自由变量的函数,被引用的自由变量和函数一同存在,即使已经离开了自由变量的环境也不会被释放或者删除,在闭包中可以继续使用这个自由变量,简单点说就是 函数 + 引用环境 = 闭包

示例

func addNum () func (int) int{
    var sum int = 0
    return func (num int) int{
        sum+=num
        return sum
    }
}
func main(){
    fn := addNum()
    fmt.Println(fn(1))  // 1
    fmt.Println(fn(1))  // 2
    fmt.Println(fn(1))  // 3
}

闭包中的变量,可以一直保存

defer 关键字

Go语言的 defer 语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。

多个 defer 执行顺序

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

输出结果:

defer begin
defer end
3
2
1

代码的延迟顺序与最终的执行顺序是反向的。延迟调用是在 defer 所在函数结束时进行,函数结束可以是正常返回时,也可以是发生宕机时。 如果像下方代码:

func main() {
    fmt.Println("print begin")
    print()
    fmt.Println("print end")
}

func print() {
    fmt.Println("defer begin")
    defer fmt.Println(1)
    defer fmt.Println(2)
    fmt.Println("defer end")
}

输出结果:

print begin
defer begin
defer end
2
1
print end