一篇文章带你了解Go语言基础之函数(中篇)

开发 后端
通常来说,defer会用在释放数据库连接,关闭文件等需要在函数结束时处理的操作。

[[433020]]

前言

Hey,大家好呀,我是星期八,上篇文章学了些基础:一篇文章带你了解Go语言基础之函数(上篇),这次咱们继续学习Go基础之函数进阶叭。

Go函数内存分配图

Go的函数内存分配,有点像堆分配,有点像,但是本质不是。

可以理解像堆内存一样,栈中保存的是堆的地址。

验证

代码

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5.  
  6. func say() string { 
  7.     return "ok" 
  8.  
  9. func main() { 
  10.     fmt.Printf("say栈上的内容:%p\n",say) 

结果

本质

函数的作用域

作用域这个问题,以前可能或多或少提过,再来复习一下叭。

全局变量

全局变量就是在所有函数外部定义的变量,程序不结束,变量就一直存在。

当然,任何函数都可以访问全局变量。

注:全局变量尽量全部用大写。

小试牛刀

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5.  
  6. var NAME = "张三" 
  7. func say() string { 
  8.     fmt.Println(NAME
  9.     return "ok" 
  10.  
  11. func main() { 
  12.     say() 
  13.     fmt.Println(NAME

结果:

上述可能会有个问题,全局变量,全局变量,大家共用一个,要是谁傻不拉几修改了不就完蛋了,整个程序都凉了。

var引发的问题

就像这样。

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. var NAME = "张三" 
  6.  
  7. func say() string { 
  8.     fmt.Println(NAME
  9.     NAME = "李四" 
  10.     return "ok" 
  11.  
  12. func main() { 
  13.     say() 
  14.     fmt.Println(NAME

结果:

这不就完犊子了吗???所以,一定要有解决办法。

使用const解决问题

解决办法:使用常量定义全局变量。

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. const NAME = "张三" 
  6.  
  7. func say() string { 
  8.     fmt.Println(NAME
  9.     //NAME = "李四"//会报错:cannot assign to NAME 
  10.     return "ok" 
  11.  
  12. func main() { 
  13.     say() 
  14.     fmt.Println(NAME
  15.  

总结

在定义全局变量时,需要用const修饰,并且变量名全部大写。

局部变量

局部变量,局部变量就是在某个函数内定义的变量,只能在自己函数内使用。

更专业点,在{}内定义的,只能在{}内使用,for同理。

代码

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.  
  6. func say() string { 
  7.     var name = "张三" 
  8.     fmt.Println(name
  9.     return "ok" 
  10.  
  11. func main() { 
  12.     say() 
  13.     //fmt.Println(name)//会报错:undefined: name 
  14.     //for同理 
  15.     for i := 0; i <= 1; i++ { 
  16.         var c = "66" 
  17.         fmt.Println(c) //66 
  18.     //fmt.Println(c)//会报错:undefined: c 

defer

在Go中,defer语句,可以理解为在return之前执行的一个语句。

如果函数没有return,会有一个默认的return,只是看不见而已。

一个defer

代码

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. func say() { 
  6.     //defer尽量往前放 
  7.     defer fmt.Println("我是666"
  8.     fmt.Println("你们都是最棒的"
  9.  
  10. func main() { 
  11.     say() 

执行结果

多个defer

代码

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. func say() { 
  6.     //defer尽量往前放 
  7.     defer fmt.Println(1) 
  8.     defer fmt.Println(2) 
  9.     defer fmt.Println(3) 
  10.     fmt.Println("你们都是最棒的"
  11.  
  12. func main() { 
  13.     say() 

执行结果

可以发现,defer的执行结果是反着的。

结论:最先执行的defer,会最后执行,最后执行的defer,会最先执行,有点像栈,先进后出。

defer的作用

通常来说,defer会用在释放数据库连接,关闭文件等需要在函数结束时处理的操作。

这里暂时先不举例子。

panic和recover

这俩,可以理解为Python中的try和raise,因为在Go中,是没有try的,是不能像其他语言一样,try所有异常。

应用场景:比如某个web,在启动时,数据库都没连接成功,必定要启动失败,就像电脑,没有电源必不能开机一样。

panic

先看一下语法吧

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. func say() { 
  6.     var flag = true 
  7.     if flag{ 
  8.         //引发错误,直接中断程序的错误 
  9.         panic("OMG,撤了撤了,必须撤了"
  10.  
  11. func main() { 
  12.     say() 
  13.     fmt.Println("继续呀...")//不会执行,程序挂了 

执行效果

可以看淡,继续呀就没打印,程序直接挂了,但是上述好像并没有解决这个问题。

recover

尝试捕捉

代码

  1. package main 
  2.  
  3. import "fmt" 
  4.  
  5. func say() { 
  6.   //匿名函数,defer执行的是一个匿名函数 
  7.   defer func() { 
  8.     var err = recover() 
  9.     //如果有panic错误,err!=nil,在此处步骤,尝试恢复 
  10.     if err != nil { 
  11.       fmt.Println("尝试恢复..."
  12.     } 
  13.   }() 
  14.   var flag = true 
  15.   if flag { 
  16.     panic("OMG,撤了撤了,必须撤了"
  17.   } 
  18.  
  19. func main() { 
  20.   say() 
  21.   fmt.Println("继续呀..."

执行结果

可以看到,如果recover捕捉了,并且没有panic,程序就会继续正常执行。

注意

defer必须在panic语句之前。

recover必须配合defer使用。

总结

上述我们学习了Go基础之函数进阶。如果在操作过程中有任何问题,记得下面讨论区留言,我们看到会第一时间解决问题。

本文转载自微信公众号「Go语言进阶学习」,可以通过以下二维码关注。转载本文请联系Go语言进阶学习公众号。

 

责任编辑:武晓燕 来源: Go语言进阶学习
相关推荐

2021-10-30 10:43:04

语言Go函数

2020-10-25 07:33:13

Go语言

2020-10-22 08:33:22

Go语言

2020-11-11 10:52:54

Go语言C语言

2020-11-05 09:58:16

Go语言Map

2022-02-16 10:03:06

对象接口代码

2020-12-07 05:59:02

语言Go接口

2020-12-09 09:59:32

Go语言技术

2022-04-27 10:01:43

切片Go封装

2020-10-23 08:38:19

Go语言

2020-12-30 09:04:32

Go语言TCPUDP

2021-10-09 07:10:31

Go语言基础

2020-12-27 10:15:44

Go语言channel管道

2020-10-22 11:15:47

Go语言变量

2021-09-29 10:00:07

Go语言基础

2021-10-13 10:00:52

Go语言基础

2021-10-16 10:17:51

Go语言数据类型

2020-12-23 08:39:11

Go语言基础技术

2021-01-13 08:40:04

Go语言文件操作

2021-02-20 10:06:14

语言文件操作
点赞
收藏

51CTO技术栈公众号