• Go的函数(function)


    函数声明

    在这里插入图片描述

    1. 关键字func。go函数声明必须以关键字func开始
    2. 函数名。函数名是指代函数定义的标识符,函数声明后,我们会通过函数名这个标识符来使用这个函数。在同一个go包中,函数名应该是唯一的,并且它也遵守go标识符的导出规则,首字母大写的函数名指代的函数是可以在包外使用的,小写就只在包内可见
    3. 参数列表。参数列表中声明了我们将要在函数体中使用的各个参数
    4. 返回值列表。返回值承载了函数执行后要返回给调用者的结果

    函数参数

    在函数声明阶段,我们把参数列表中的参数叫做形式参数,在函数体中,我们使用的都是形参;在函数实际调用时传入的参数被称为实际参数
    在这里插入图片描述
    Go 语言中,函数参数传递采用是值传递的方式。所谓“值传递”,就是将实际参数在内存中的表示逐位拷贝(Bitwise Copy)到形式参数中

    1. 对于像整型、数组、结构体这类类型,它们的内存表示就是它们自身的数据内容,因此当这些类型作为实参类型时,值传递拷贝的就是它们自身,传递的开销也与它们自身的大小成正比
    2. 像 string、切片、map 这些类型就不是了,它们的内存表示对应的是它们数据内容的“描述符”。当这些类型作为实参类型时,值传递拷贝的也是它们数据内容的“描述符”,不包括数据内容本身,所以这些类型传递的开销是固定的,与数据内容大小无关。这种只拷贝“描述符”,不拷贝实际数据内容的拷贝过程,也被称为“浅拷贝”

    函数为何是go语言中的一等公民

    go函数可以存储在变量中

    支持在函数内创建并通过返回值返回

    闭包本质上就是一个匿名函数或叫函数字面值,它们可以引用它的包裹函数,也就是创建它们的函数中定义的变量。然后,这些变量在包裹函数和匿名函数之间共享,只要闭包可以被访问,这些共享的变量就会继续存在

    作为参数传入函数

    拥有自己的类型

    每个函数声明定义的函数仅仅是对应的函数类型的一个实例,就像var a int = 13这个变量声明语句中的a,只是int类型的一个实例一样

    函数健壮性

    健壮性“三不要”原则

    不要相信任何外部输入的参数

    函数需要对所有输入的参数行合法性的检查。一旦发现问题,立即终止函数的执行,返回预设的错误

    不要忽略任何一个错误

    在我们的函数实现中,也会调用标准库或第三方包提供的函数或方法。对于这些调用,我们不能假定它一定会成功,我们一定要显式地检查这些调用返回的错误值。一旦发现错误,要及时终止函数执行,防止错误继续传播

    不要假定异常不会发生

    panic

    panic指的是go程序在运行时出现的一个异常情况。如果出现异常了,但没有被捕获并恢复,go程序的执行就会被终止,即便出现异常的位置不在主goroutine中也会这样

    来源
    1. go运行时
    2. go开发人员通过panic函数主动触发的
    recover函数(捕捉panic并恢复程序正常执行秩序的方法)
    func bar() { 
        defer func() { 
            if e := recover(); e != nil { 
                fmt.Println("recover the panic:", e) 
            } 
        }() 
        println("call bar") 
        panic("panic occurs in bar") 
        zoo() 
        println("exit bar")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    recover 是 Go 内置的专门用于恢复 panic 的函数,它必须被放在一个 defer 函数中才能生效。如果 recover 捕捉到 panic,它就会返回以 panic 的具体内容为错误上下文信息的错误值。如果没有 panic 发生,那么 recover 将返回 nil。而且,如果 panic 被 recover 捕捉到,panic 引发的 panicking 过程就会停止

    如何应对
    1. 评估程序对panic的忍受度
    2. 提示潜在bug。在go标准库中,大多数panic的使用都是充当类似断言的作用的
    3. 不要混淆异常与错误

    函数的简洁性

    使用defer简化函数实现

    defer的运作机制

    defer是go语言提供的一种延迟调用机制,defer的运作离不开函数

    1. 在go中,只有在函数(和方法)内部才能使用defer
    2. defer关键字后面只能接函数(或方法),这些函数被称为deferred函数。defer将它们注册到其所在Goroutine中,用于存放deferred函数的栈数据结构中,这些deferred函数将在执行defer的函数退出前,按后进先出(LIFO)的顺序被程序调度执行

    在这里插入图片描述

    defer的使用注意事项

    明确哪些函数可以作为deferred函数

    对于自定义的函数或方法,defer 可以给与无条件的支持,但是对于有返回值的自定义函数或方法,返回值会在 deferred 函数被调度执行的时候被自动丢弃

    注意defer关键字后面表达式的求值时机

    defer关键字后面的表达式,是在将deferred函数注册到deferred函数栈的时候进行求值的

    知晓defer带来的性能损耗
  • 相关阅读:
    力扣学习记录(每日更新)
    elform-item动态prop
    佳兆业深陷债务围城,重组方案悬而未定
    斯坦福机器学习 Lecture3
    排序(order by)
    javabasic
    时间序列聚类的直观方法
    Azkaban安装及配置
    代码随想录算法训练营第五十七天 | 动态规划 part 15 | 392.判断子序列、115.不同的子序列
    黑马Java笔记第九讲—ArrayList集合和学生管理系统
  • 原文地址:https://blog.csdn.net/lee_nacl/article/details/127811328