Go语言基础(4)-- 函数

四、函数

Go语言中的函数传参永远是拷贝

4.1、函数概念

● 函数就是将一堆代码进行重用的一种机制。函数就是段代码, 一个函数就像一个专门做这件事的人,调用它来做一些事情,它可能需要提供一些数据给它,它执行完成后可能会有一些执行结果。要求的数据就叫参数,返回的执行结果就是返回值

注意:所有的函数都是全局函数可以被项目中所有文件使用在项目中,所以函数名是唯一的

● Go语言拒绝使用默认参数,没有默认参数的概念

4.2、函数定义

基本格式:

func 函数名(形式参数名 数据类型,形式参数名 数据类型.....)(返回值名称 返回值类型){

//函数体

}

参数可以不命名,返回值也可以不命名。

命名返回值,相当于已经声明了一个变量。

当参数都是同一类型时,可省略前几个的类型声明

func f1(x, y, z int,m ,n string ,u ,v,w [5]int) {

}

4.3、函数调用

函数名(实际参数,实际参数…)

注意:形参和实参是不同的存储单元

调用过程图示:

在这里插入图片描述

4.4、不定参函数

4.4.1、定义格式:

func test(args ...int){
	len(args)//切片的长度

}

以切片的形式接收

注意:可变长参数必须放在参数最后

4.4.2、嵌套使用

func test4(b ...int) {  for i := 0; 1 < len(b); i++ {   fmt.Println(i, b[i])  }}func test3(a ...int) {   test4(a[0:]...)//从下标0开始到最后 test4(a[:2]...)//从开始到下表为2不包括2 test4(a[1:3]...)//从下标为1到下标为3不包括3}

4.5、带有返回值的函数

定义格式①(默认):

func sub(a int ,b int ) int {
  sum:=a-b
  //return表示函数的结束,匿名的返回值,必须指定返回的变量
  return sum
}

return后面的代码不会执行

定义格式②(单个返回值):

func sub(a int, b int) (sum int) {
  sum = a - b
  //return表示函数的结束,声明了返回值,就可以不写返回值。

  return 
}

定义格式③(多个返回值):

func sub(a int, b int) (sum int, b int ,c  int) {
  sum ,b,c = 1,2,3
  //return表示函数的结束
  return 
}
func main(){

	a,b,c := sub(10,20)

	e,_,f := sub(10,20)

}

4.6、函数类型

本质是一个指针

4.6.1、type

type 的作用:

① 定义函数类型。

② 为已存在的函数起别名。

func test1() {
  fmt.Println("hello ")
}
func test2(a int, b int){
  fmt.Println( a + b )
}
type FUNCTYPE func()//大小写均可以
type FUNCTEST func(int, int)
func main() {
  //定义函数类型变量
  var f FUNCTYPE
  f = test1
  //通过函数变量调用函数
  f()
  f1 := test2
  f1(10,20)
}

4.7、函数的作用域

局部变量:在函数内部定义的变量,作用域限定于本函数内部从变量定义到本函数结束有效。在同一作用域范围内变量名是唯一的。

全局变量:既能在一个函数中使用,也能在其他的函数中使用。定义在函数外部的变量就是全局变量。全局变最在任何的地方(项目中所有文件)都可以使用,不存在先声明后定义或先定义后声明的区别。全局变量存储在数据区。

● const常量:常量存储位置是数据区。

● 函数中查找变量的顺序

​ 1.先在函数内部查找。

​ 2.找不到就往函数的外面查找。一直找到全局变量

4.8、匿名内部函数

定义函数的时候,是不能在一个函数中,再次定义一个函数。如果想在一个函数中再定义一个函数,可以使用匿名函数,所谓匿名函数就是没有名字的函数。

4.8.1、不带返回值的匿名函数

定义:

func (a int, b int) {
  fmt.Println(a + b)
  }(10, 20)

或者:

{

 }

重复利用:

f:=func(a int, b int) {
  fmt.Println(a + b)
   }
  f(10,20)

4.8.2、带返回值的匿名函数

v := func(a int, b int) int {
  return a + b
  }(10, 20)//已经调用了
	 fmt.Println(v)    //30
	fmt.Printf("%T", v) //int

重复利用:

m := func(a int, b int) int {
  return a + b
  }
  fmt.Printf("%T",m)//func(int, int) int

a := m(5, 6)

fmt.Println(a)//11

4.9、闭包

闭包:是指 有权访问另一个函数作用域中的变量的函数。函数包含了他外部作用域的一个变量。

● 在Go语言里,所有的匿名函数(Go语言规范中称之为函数字面量)都是闭包。

● 根据以上定义,那么匿名函数其实就是闭包

● 也可以这样理解闭包:虽然不能在一个函数里直接声明另一个函数,但是可以在一个函数中声明一个函数类型的变量,此时的函数称为闭包(closure)

● 作用:可以通过匿名函数和闭包实现函数在栈区的本地化

举例:

func adder(x int) func(int) int {
  return func(y int) int {
   x += y
   return x
  }
}
func main() {
  ret := adder(100)//包含函数返回值(一个函数)以及变量X
  ret2 := ret(200)
  fmt.Println(ret2)
}


func test222() func() int {
  var a int
  return func() int {
     a++
     return a
  }
}
func main() {
  //将test222函数类型赋值给m
  //m:=test222
  //函数调用将test222的返回值给f
  f := test222()
  for i := 0; i < 10; i++{
   fmt.Println(f())
  }
}

等价于:

func main() {
  var a int
  f := func() int {
   a++
   return a
  }
  for i := 0; i < 10; i++{
   fmt.Println(f())
  }
}

4.10、递归函数

● 如果一个函数在内部不调用其它的函数,而是自己本身的话,这个函数就是递归函数

● 递归函数一定要有出口。

● 函数执行流程图:

在这里插入图片描述

4.11、defer语句

● Go语言中的defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。

● 多用于函数执行完之前释放资源

● defer 执行函数时,会先将函数参数值传进去,函数值是函数时,会优先执行此函数。(举例③)

4.11.1、举例

func demo() {
  fmt.Println("1..........")
  defer fmt.Println("2..........")
  fmt.Println("3..........")
  fmt.Println("4..........")
}
func main() {
  demo()
}

在这里插入图片描述

func demo() {
  fmt.Println("1..........")
  defer fmt.Println("2..........")
  defer fmt.Println("3..........")
  fmt.Println("4..........")
  fmt.Println("5..........")
}
func main() {
  demo()
}

在这里插入图片描述

func calc(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret
}
func main() {
	a := 1
	b := 2
	defer calc("1", a, calc("10", a, b))
	a = 0
	defer calc("2", a, calc("20", a, b))
	b = 1
}

在这里插入图片描述

4.11.2、执行时机

在Go语言的函数中 return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:

在这里插入图片描述

func f1() int {
  x := 5
  defer func() {
   x++
  }()
  return x
}
func f2() (x int) {
  defer func() {
   x++
  }()
  return 5
}
func f3() (y int) {
  x := 5
  defer func() {
   x++
  }()
  return x
}
func f4() (x int) {
  defer func(x int) {
   x++
  }(x)//传参
  return 5
}

func main() {
  fmt.Println(f1()) //5
  fmt.Println(f2()) //6
  fmt.Println(f3()) //5
  fmt.Println(f4()) //5
}

4.12、内置函数

在这里插入图片描述

panic/recover

Go语言中目前( Go1.12 )是没有异常机制,但是使用panic/recover 模式来处理错误,panic 可以在任何地方引发,但 recover只有在defer 调用的函数中有效。

注意:recover是恢复错误前的状态,禁止滥用,最好少用。

func funcA() {
  fmt.Println("a")
}
func funcB() {
  panic("出现了严重的错误! ! ! ") //程序崩溃退出
  fmt.Println("b")
}
func funcC() {
  fmt.Println("c")
}
func main() {
  funcA()
  funcB()
  funcC()
}

在这里插入图片描述

func funcA() {
  fmt.Println("a")
}
func funcB() {
  defer func() {
   err := recover()
   fmt.Println(err)
   fmt . Println("释放数据库连接...")
  }()
  panic("出现了严重的错误! ! ! ") //程序崩溃退出
  fmt.Println("b")
}
func funcC() {
  fmt.Println("c")
}
func main() {
  funcA()
  funcB()
  funcC()
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值