09-Go语言函数

函数

  • 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函数 --> 执行逻辑代码 --> 退出程序


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容