第6课 Go函数func&defer

lhdalhd1996 · · 1387 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Go语言函数的基本用法!

package main

import (
    "fmt"
)

/*
    函数function
    -Go函数不支持嵌套、重载、默认参数
    -但支持以下特性:
        无序声明原型,不定长度变参,多返回值,命名返回值参数
        匿名函数,闭包
    -定义函数使用关键字func,且左大括号不能另起一行
    -函数也可以作为一种类型使用
*/

func A(a int, b string, c int) int {
    //代表参数有三个,返回值是一个int型
    return 1
}
func B(a, b, c int) {
    //参数也可以这样写
}
func C() (a, b, c int) {
    a = 1
    b = 1
    c = 1  //代表返回值a,b,c,注意在此处abc已经是局部变量
    return //在这里可以省略abc,因为abc是唯一的,它是局部变量
}

func D(b string, a ...int) { //不定长变参的使用,注意不定长变参只能作为参数列表最后一个参数
    fmt.Println(a)
}

func E(s ...int) {
    s[0] = 3
    s[1] = 4
    //可见传入的是一个slice类型
    fmt.Println(s)
} //不定长变参传入的是个slice,但是是个拷贝,这个和直接传入slice不同

func F(s []int) {
    //不是传入了指针,是拷贝的是地址,所以可以改变主函数中的那个slice
    s[0] = 3
    s[1] = 4
    fmt.Println(s)
}

func G() {
    fmt.Println("this is G!")
}

func H(x int) func(int) int {
    return func(y int) int {
        return x + y
    }
} //这个函数参数是int x,而返回值是函数!
func main() {
    D("s", 2, 3, 4) //输出结果[2 3 4],可见"s"被b读取,2,3,4被a读取。
    fmt.Println("------")

    a, b := 1, 2
    E(a, b)           //输出[3,4]
    fmt.Println(a, b) //输出1,2
    //由此可见,实际上传入E的是一个slice的拷贝,并不是slice本身
    fmt.Println("------")

    s := []int{1, 2}
    F(s)           //输出[3 4]
    fmt.Println(s) //输出[3 4]
    fmt.Println("------")

    c := G
    c() //输出this is G!
    //可见,函数也可以作为类型,在Go语言中,一切皆类型啊!
    fmt.Println("------")

    d := func() {
        fmt.Println("我是匿名函数!")
    }
    d()
    fmt.Println("------")
    //这个例子创建了匿名函数!

    e := H(10)
    fmt.Println(e(1))
    fmt.Println(e(2))
    //闭包(虽然我不懂)
}

defer
-的执行方式类似其他语言中的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行
-即使函数发生严重错误也会执行
-支持匿名函数的调用
-常用于清理资源、文件关闭、解锁以及记录时间等操作
-通过与匿名函数配合可在return之后修改函数计算结果
-如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则则是引用某个变量的地址

-Go没有异常机制,但是有panic/recover模式来处理错误
-Panic可以在任何地方引发,但recover只有在defer调用的函数中有效

defer的普通调用

package main

import "fmt"

func main() {
    fmt.Println("a")
    defer fmt.Println("b")
    defer fmt.Println("c")
    fmt.Println("-----")
}
/*运行结果
[ `go run temp.go` | done: 874.0399ms ]
  a
  -----
  c
  b
*/ //在函数体执行结束后按照调用顺序的相反顺序逐个执行


package main

import "fmt"

func main() {
    for i := 0; i < 3; i++ {
        defer fmt.Println(i)
    }
}
/*运行结果
[ `go run temp.go` | done: 652.4791ms ]
  2
  1
  0
*/

闭包下的defer

package main

import "fmt"

func main() {
    for i := 0; i < 3; i++ {
        defer func() {
            fmt.Println(i)
        }() //最后这对括号的作用是调用这个函数,如A()是调用A函数,Sum()是调用Sum函数
    }
}

/*运行结果如下
[ `go run temp.go` | done: 705.7846ms ]
  3
  3
  3
*/ //这里的i是用的引用类型,在退出循环之后,i已经是3了。而上一个例子是每循环一次defer一个fmt.Println(i),相当于复制进去了。
//这是闭包使用的时候的特殊情况

defer配合recover()使用
注意:panic(“Panic!”)发生后,recover()函数可以检测到,并且返回一个指针,我们用一个变量来接受,并且判断这个指针是否为nil,如果为nil就说明没有引发panic,否则引发了panic,还有recover()必须在defer的函数内部使用。

package main

import "fmt"

func main() {
    A()
    B()
    C()
}

func A() {
    fmt.Println("Func A")
}

func B() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("Recover in B")
        }
    }()
    panic("Panic in B")
}
func C() {
    fmt.Println("Func C")
}

/*运行结果如下:
[ `go run temp.go` | done: 727.6154ms ]
  Func A
  Recover in B
  Func C
*/

slice 和 map 都是引用类型的拷贝
匿名函数不能作为顶级函数,最外层函数不能是匿名函数
defer-panic-recover体制
panic用于处理如数组越界等无法恢复的错误
recover函数可以从panic状态恢复过来
注意defer的执行顺序


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:lhdalhd1996

查看原文:第6课 Go函数func&defer

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1387 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传