美文网首页
09-Go语言函数

09-Go语言函数

作者: 喝酸奶要舔盖__ | 来源:发表于2018-09-21 11:34 被阅读0次

    函数

    • Go语言函数格式
      • func 函数名称(形参列表)(返回值列表){函数语句}
    • Go语言函数的类型
      • 没有返回值没有形参的函数
      func test() {
       fmt.Println("我是一个没返回值没形参的函数")
      }
      
      • 有返回值没有形参的函数
      //注意点: 当返回值只有一个的时候可以省略返回值列表的()
      func test2() int {
       return 10
      }
      
      • 没有返回值有形参的函数
      //注意点: 返回值列表类型相同前面可以省略类型,直接写在后面即可
      func sum() (num, value int) {
       num = 10
       value = 20
       return //这里可以不写变量默认就是返回定义的返回值变量
      }
      
      • 有返回值有形参的函数
       //多个连续相同类型的形参,可以只在后面写上一个数据类型
       func minus(a, b int) (value int) {
         value = a - b
         return
      }
      
    • Go语言函数注意点

    1.在C语言中函数定义在main函数后面,需要先声明再调用
    在Go语言中可以不用声明直接使用
    2.Go语言中如果函数只有一个返回值, 那么返回值列表的()可以省略
    3.Go语言中如果有返回值,可以在返回值列表中定义变量,函数中可以直接使用
    4.如果在返回值列表中定义了变量, 那么return后面可以不用写任何内容, 默认就会将返回值列表中定义的变量返回
    5.Go语言中一个函数可以有多个返回值
    6.如果一个函数有多个返回值, 但是我们只想使用其中的一个, 那么可以在接收的时候使用_来忽略, 不需要的那个返回值
    7.因为_(下划线)在Go语言中有特殊的含义, 所以在定义标识符的时候_(下划线)不能单独作为标识符
    8.如果返回值列表中有多个返回值, 并且连续的多个返回值的数据类型都一样, 那么只用在最后一个变量后面添加数据类型即可
    9.如果形参列表中有多个形参, 并且连续的多个形参的数据类型都一样, 那么只用在最后一个变量后面添加数据类型即可


    值传递和引用传递

    • 值传递
      • 在C语言中基本数据类型作为函数的参数,是值传递,函数内部修改形参不会影响外面的实参值
      • Go语言和C语言一样, bool float int
      package main
      
      import "fmt"
      
      func main() {
        value := 10
        fmt.Println(value)
        change(value)
        fmt.Println(value)
      }
      
      func change(num int) {
         num = 888
      }
      
    • 引用传递
      • 如果想要修改外界的实参,需要函数接收指针类型
      package main
      
      import "fmt"
      
      func main() {
        num := 20
        fmt.Println(num) //20
        change2(&num)
        fmt.Println(num) //666
      
      }
      func change2(num *int) {
        *num = 666
      }
      

    匿名函数

    • 匿名函数概念

      • 普通函数都有函数名称,匿名函数就是没有名字的函数
    • 使用匿名函数注意点

    3.1匿名函数定义之后, 如果没有立即调用, 编译器会报错
    3.2也可以将一个匿名函数保存到一个变量中
    在C语言中我们知道, 我们可以定义一个指向函数的指针来保存函数的地址, 然后通过指针来调用函数
    在Go语言中函数是一等公民(可以定义变量, 作为形参, 作为返回值), 所以在Go语言中也可以用函数类型来定义变量(相当于C语言中指向函数的指针)
    3.3由于函数是一等公民, 所以以前定义变量所有的格式, 都可以用于定义函数类型的变量
    var 变量名称 函数类型
    var 变量名称 函数类型 = 匿名函数
    var 变量名称 = 匿名函数
    变量名称 := 匿名函数
    var(
    变量名称 = 匿名函数
    )

    //定义一个匿名函数,立即调用自己,直接在匿名函数后面加上()
        func(){
            fmt.Printf("我是一个匿名函数,然后立即调用")
        }()
    
    //这种方法可以查看匿名函数是什么类型的函数
        f := func() {
            fmt.Println("我是一个匿名函数")
        }
        fmt.Printf("%T\n", f)
    
    // 定义一个函数类型的变量, 保存匿名函数
    
        var f func() = func() {
            fmt.Println("我是一个匿名函数")
        }
        //然后通过函数类型的变量调用匿名函数
        f()
    
    • 匿名函数应用场景
      一般情况下,某个函数只调用一次,会只用匿名函数作为函数的参数,或者返回值
      • 匿名函数作为参数传递
      package main
      
      import "fmt"
      
      func main() {
        //1.匿名函数在外部定义,然后传给函数
        //fn将来可以保存所有接收两个int类型形参返回一个int类型结果的函数
        var fn func(int, int) int = func(a, b int) int {
              res := a + b
              return res
          }
        
          res := calculate(10, 20, fn)
          fmt.Println(res)
      
        //2.匿名函数直接在函数中定义
        res1 := calculate(20,20, func(a int, b int) int {
            value := a * b
            return value
        })
      
        fmt.Println(res1)
      }
      
      func calculate(num, value int, method func(int, int) int) int {
          res := method(num, value)
          return res
      }
      
      • 匿名函数作为返回值
      package main
      
      import "fmt"
      
      func main() {
        //定义一个函数类型变量接收这个函数三种方式
      
        //var fn func(int, int) int = test()
        //var fn = test()
        fn := test()
        //通过变量调用匿名函数,定义一个变量接收匿名函数的返回值
        res := fn(10,20)
        fmt.Println(res)
      }
      
      //匿名函数作为函数的返回值
      func test() func(int, int) int {
        return func(num int, value int) int {
            res := num + value
            return res
        }
      }
      

    闭包

    • 闭包的概念
      • 闭包就是一个特殊的匿名函数,只要这个匿名函数使用到了外界的变量,那么这个匿名函数就叫做闭包
        注意点:只要闭包还在使用外界的变量,那么这个外界的变量就会一直存在
      package main
      
      import "fmt"
      
      func main() {
        fn := addUpper()
        fn() //2
        fn() //3
        fn() //4
      }
      
      func addUpper() func() {
        x := 1 //2 //3
        return func() {
            x++
            fmt.Println(x) // 2 , 3 , 4
        }
      }
      

    延迟调用

    • defer语句常用于释放资源解除锁定以及错误处理
      • 例如C语言中我们申请了一块内存空间,那么不使用时我们就必须释放这块存储空间
      • 例如C语言中我们打开了一个文件,那么我们不使用时就要关闭这个文件
      • 例如C语言中我们打开了一个数据库, 那么我们不使用时就要关闭这个数据库
      • 这一类的操作在Go语言中都可以通过defer语句来完成
      //defer语句会在main函数执行完再执行
        fmt.Println("申请了存储空间")
        defer fmt.Println("释放了存储空间")
        fmt.Println("使用了存储空间")
        fmt.Println("使用了存储空间")
        fmt.Println("使用了存储空间")
      
    • 无论你在什么地方注册defer语句,它都会在所属函数执行完毕之后才会执行, 并且如果注册了多个defer语句,
      那么它们会按照后进先出的原则执行
      • 正是因为defer语句的这种特性, 所以在Go语言中关闭资源不用像C语言那样用完了再关闭, 我们完全可以打
        开的同时就关闭, 因为无论如何defer语句都会在所属函数执行完毕之后才会执行
        //多个defer语句执行顺序
        defer fmt.Println("释放了存储空间1")
        defer fmt.Println("释放了存储空间2")
        defer fmt.Println("释放了存储空间3")
        defer fmt.Println("释放了存储空间4")
      
      

    init函数

    • Go语言中保留了两个函数
      • main函数,由系统自动调用
      • init函数,也是由系统地洞调用
      • 这两个函数在定义时不能有任何的参数和返回值
    • 注意点
      • main函数只能在main包中(package main), 并且一个程序只能有一个
      • 但是init函数每个包中都可以有, 并且可以有多个(但是企业开发推荐只写一个)
    • init函数的作用
      • init函数用于处理当前文件的初始化操作, 在使用某个文件时的一些准备工作应该放到这里
    • 多个包程序执行的调用顺序
      • 加载main包
      • 初始化import导入的包(初始化常量 -->初始化全局变量 --> 执行init函数 --> 执行逻辑代码)
      • 初始化常量 --> 初始化全局变量 --> 执行init函数 --> 执行main函数 --> 执行逻辑代码 --> 退出程序


    相关文章

      网友评论

          本文标题:09-Go语言函数

          本文链接:https://www.haomeiwen.com/subject/nbranftx.html