码迷,mamicode.com
首页 > 其他好文 > 详细

Golang基础_06-函数function

时间:2019-08-23 19:15:30      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:command   class   ref   ola   部分   func   遇到   传递   recover   

目录

@

Tips

  • Go函数不支持 嵌套,重载 和 默认参数
  • 但支持以下特性: 无需声明原型,不定长度变参,多返回值,命名返回值参数,匿名函数,闭包
  • 定义函数使用关键字func,并且左大括号不能另起一行

    函数定义,不定长变参,传递值类型与引用类型

func main(){
    a,b := 1,2
    //传入值类型的拷贝,(int,string),不会改变这里的值
    B(a,b)
    fmt.Println("a,b=",a,b)
    fmt.Println(A())
    ss := []int{5,6,7,8}
    //传入的参数是slice,是数组地址的拷贝,会改变这里的值,类似指针
    C(ss)
    fmt.Println("ss=",ss)
}
func A()(int, int, int){
    a,b,c := 1,2,3
    return a,b,c
}
func B(s ...int){
    //a是个slice,不定长变参,只能作为最后一个参数
    s[0]=3
    s[1]=4
    fmt.Println("s=",s)
}
func C(s []int){
    s[0] = 55
    s[1] = 66
    s[2] = 77
    s[3] = 88
    fmt.Println(s)
}
/*
> Output:
command-line-arguments
s= [3 4]
a,b= 1 2
1 2 3
[55 66 77 88]
ss= [55 66 77 88]
*/
  • 值类型传递和引用类型传递都是拷贝,但是值类型是拷贝值,而引用类型是拷贝地址

    一切皆类型,包括函数

  • Go语言中,一切皆类型,函数也能作为一种类型使用

func main(){
    a := A
    a()
}
func A(){
    fmt.Println("Func A")
}
/*
> Output:
command-line-arguments
Func A
*/

匿名函数和闭包

匿名函数

-匿名函数不能是最外层函数

func main(){
    a := func(){
        fmt.Println("Func A")
    }
    a()
}
func A(){
    fmt.Println("Func A")
}
/*
> Output:
command-line-arguments
Func A
*/

闭包

  • 闭包函数的作用:返回一个匿名函数
func main(){
    f := closure(10)
    fmt.Println(f(1))
    fmt.Println(f(2))
}
func closure(x int) func(int) int {
    fmt.Printf("outside %p\n", &x)
    return func(y int) int {
        fmt.Printf("%p\n", &x)
        return x * y
    }
}
/*
> Output:
command-line-arguments
outside 0xc042054080
0xc042054080
10
0xc042054080
20
*/

defer用法

  • defer的执行方式类似其他语言的析构函数,在函数体执行结束后,按照调用顺序的相反顺序执行(好像递归返回那样吧)
  • 就算函数发生了严重错误也会执行
  • 支持匿名函数的使用
  • 常用于资源清理,文件关闭,解锁以及记录时间等操作
  • 通过与匿名函数配合可以在return之后修改函数结果
  • 如果函数体内某个变量作为defer时匿名函数的参数,则在定义时就已经获得拷贝,否则则是引用某个变量的地址
func main(){
    fmt.Println("a")
    defer fmt.Println("b")
    defer fmt.Println("c")
}
//a,c,b
  • 把return语句看做赋值+返回RET指令两部分,defer是插入在中间的,并且注意defer里面的函数操作的是返回值还是别的变量,匿名函数的参数是值传递还是引用传递,值传递就不会改变返回值啦
  • 参照大佬解析
  • 注意:defer后面定义的匿名函数要在最后加上(参数)
func main(){
    for i:=0; i<3; i++ {
        defer func() {
            fmt.Println(i)
            }()
    }
    fmt.Println("a")
    defer fmt.Println("b")
    defer fmt.Println("c")
}
/*
> Output:
command-line-arguments
a
c
b
3
3
3
*/

panic 与 recover,错误处理机制

  • Go没有异常机制,但是panic/recover模式来处理错误
  • panic可以在任何地方引发,但是recover只有在defer调用的函数
func main(){
    A()
    B()
    C()
}
func A() {
    fmt.Println("Func A")
}
//defer要放在panic前面才有效,程序遇到panic就停了,所以要在这之前先注册defer的函数,且panic语句也不会执行了
func B() {
    defer func() {
        if err:=recover(); err!=nil{
            fmt.Println("recover in B")
        }
    }()
    panic("panic in B")
}
func C() {
    fmt.Println("Func C")
}
/*
> Output:
command-line-arguments
Func A
recover in B
Func C
*/

综合例子

func main(){
    var fs = [4]func(){}
    for i := 0; i<4; i++ {
    //值拷贝i+defer先进后出的输出
        defer fmt.Println("defer i= ",i)
        //引用拷贝(匿名函数没有参数,引用的i是外层的地址拷贝,为4)+defer
        defer func() {fmt.Println("defer_closure i= ",i)}()
        //引用拷贝(匿名函数没有参数,引用的i是外层的地址拷贝,为4)
        fs[i] = func(){ fmt.Println("closure i= ",i)}
    }
    for _,f := range fs {
        f()
    }
}
/*
> Output:
command-line-arguments
closure i=  4
closure i=  4
closure i=  4
closure i=  4
defer_closure i=  4
defer i=  3
defer_closure i=  4
defer i=  2
defer_closure i=  4
defer i=  1
defer_closure i=  4
defer i=  0
*/

Golang基础_06-函数function

标签:command   class   ref   ola   部分   func   遇到   传递   recover   

原文地址:https://www.cnblogs.com/leafs99/p/golang_basic_06.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!