Go语言核心编程---06函数、包和错误处理

6.1 函数

6.1.1 函数的基本语法

func 函数名 (形参列表) (返回值列表){

    执行语句...

    return 返回值列表

}

  • 形参列表:表示函数的输入

  • 函数中的语句:表示为了实现某一功能代码块

  • 函数可以有返回值,也可以没有

6.1.2 函数使用的注意实现和细节讨论
  • 函数的形参列表可以是多个,返回值列表也可以是多个。

  • 形参列表和返回值列表的数据类型可以是值类型和引用类型。

  • 函数的命名遵循标识符命名规范,首字母不能是数字。首字母大写该函数可以被本包文件和其他包文件使用;首字母小写只能被本包文件使用,其它包不能使用。

  • 函数中的变量是局部的,函数外不生效。

  • 基本数据类型和数组是默认值传递的,即进行值拷贝。在函数内修改不会影响到原来的值。

  • 如果希望函数内的变量能修改函数外的变量(指默认以值传递的方式传递的数据类型),可以传入变量的地址&,函数内以指针的方式操作变量,从效果上看类似引用。

  • Go函数不支持函数重载。

  • 在Go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量,通过该变量对函数调用。 因此,函数也可以作为形参并且调用。

  • 为了简化数据类型定义,Go支持自定义数据类型。type 自定义数据类型名 数据类型

  • 支持对函数返回值命名,如:a, b = myFunction(c,d),a、b就是对返回值命名。

  • 使用"_"标识符,忽略返回值。

  • Go支持可变参数,可变参数需要放在形参列表最后。


//args是slice切片,通过args[index]可以访问到各个值

//支持0到多个参数

func sum(args... int) sum int {

}

//支持1到多个参数

func sum(n1 int, args... int) sum int {

}

//例子

func sum(n1 int, args... int) int {

    sum := n1

    for i := 0; i < len(args); i++ {

        sum += args[i]

    }

    return sum

}

res := sum(10, -1, 2, 90, 0) // 10是n1,-1开始是args

fmt.Println("res=", res)

6.1.3 init函数

每一个源文件都可以包含一个init函数,该函数会在main函数执行前被Go运行框架调用。

  • 注意事项

    • 如果一个文件同时包含全局变量定义、init函数和main函数,则执行的流程:全局变量定义—init函数—main函数

    • 如果main包(全局变量定义、init函数、main函数)引用了go包(全局变量定义、init函数),且执行的流程:go全局变量定义—go init函数—main全局变量定义—main init函数—main main函数

6.1.4 匿名函数

Go支持匿名函数,匿名函数就是没有名字的函数,如果我们某个函数只希望使用一次,可以考虑使用匿名函数,匿名函数也可以实现多次调用。

  • 使用方式1(只能调用一次):

res := func (n1 int, n2 int) int {

    return n1 + n2

} ( 10, 20)

fmt.Println("res = ", res) //30

  • 使用方式2(将匿名函数赋给一个变量,再通过这个变量来调用匿名函数):

a := func (n1 int, n2 int) int {

    return n1 - n2

}

res = a(10, 30)

fmt.Println("res = ", res) //-20

  • 全局匿名函数

如果将匿名函数赋给一个全局变量,那么这个匿名函数就成为一个全局匿名函数,可以在程序有效。

6.1.5 函数的defer

在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等),为了在函数执行完毕后,及时地释放资源,Go的设计者提供defer。


package main

import "fmt"

func sum(n1 int, n2 int) int {
   
   //当执行到defer时,会将defer后面的语句压入到独立的栈,暂时不执行
   //当函数执行完毕后,再从栈中按照先进后出的方式执行(即栈的特性)
   defer fmt.Println("ok1 n1 = ", n1) //执行3
   defer fmt.Println("ok2 n2 = ", n2) //执行2
   res := n1 + n2
   fmt.Println("ok3 res = ", res) //执行1
   return res
}

func main() {
   
   res := sum(10, 20)
   fmt.Println("res = ", res) //执行4
}
  • defer的注意事项和细节:

    • 当go执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入到一个栈中,然后继续执行函数下一语句。
  • 当函数执行完毕后,再从defer中依次从栈顶取出语句执行(遵循栈先进后出的原则)。

  • 在defer将语句放入栈时,也会将相关的值拷贝同时入栈。


package main

import "fmt"

func sum(n1 int, n2 int) int {
   //当执行到defer时,会将defer后面的语句压入到独立的栈,暂时不执行
   //当函数执行完毕后,再从栈中按照先进后出的方式执行(即栈的特性)
   defer fmt.Println("ok1 n1 = ", n1) //执行3
   defer fmt.Println("ok2 n2 = ", n2) //执行2
   n1++ //这句话不会影响栈中存放的n1值,仍然为10
   n2++ //同理,栈中的n2仍然为20
   res := n1 + n2
   fmt.Println("ok3 res = ", res) //执行1
   return res
}

func main() {
   res := sum(10, 20)
   fmt.Println("res = ", res) //执行4
}
  • defer的最佳实践:defer最重要的价值在于当函数执行完毕后,可以及时的释放函数创建的资源。

    • 在Go编程中的通常做法是,创建资源后(如打开了文件、获取了数据库的连接、或者锁资源),可以执行defer file.Close()defer connect.Close()

    • 在defer后,可以继续使用创建资源

    • 当函数完毕后,系统会依次从栈中,取出语句关闭资源


//模拟代码如下

func test(){

    file = openfile(文件名)

    defer file.close()

    //其他代码

    

    connect = ope
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值