Go后端开发 -- 条件、循环语句 defer语句

Go后端开发 – 条件、循环语句 && defer语句

文章目录

  • Go后端开发 -- 条件、循环语句 && defer语句
  • 一、条件语句
    • 1.if ... else 语句
    • 2.switch语句
    • 3.select语句
  • 二、循环语句
    • 1.for循环
  • 三、defer语句
    • 1.defer语句的作用
    • 2.defer和return的先后顺序
    • 3.recover错误拦截


一、条件语句

1.if … else 语句

语法:

if 布尔表达式 {/* 在布尔表达式为 true 时执行 */
} else {/* 在布尔表达式为 false 时执行 */
}

与C的if … else语句的区别是条件不用加括号
实例

package mainimport "fmt"func main() {/* 局部变量定义 */var a int = 100;/* 判断布尔表达式 */if a < 20 {/* 如果条件为 true 则执行以下语句 */fmt.Printf("a 小于 20\n" );} else {/* 如果条件为 false 则执行以下语句 */fmt.Printf("a 不小于 20\n" );}fmt.Printf("a 的值为 : %d\n", a);
}

2.switch语句

语法:

switch var1 {case val1:...case val2:...default:...
}
  • switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break
  • switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough
  • 变量 var1 可以是任何类型,而 val1 和 val2 则可以是同类型的任意值。类型不被局限于常量或整数,但必须是相同的类型;或者最终结果为相同类型的表达式
  • 可以同时测试多个可能符合条件的值,使用逗号分割它们,例如:case val1, val2, val3
  • switch语句可以不在switch开头确定判断的条件,可以在case中进行条件判断;

实例:

package Switchimport "fmt"func Switch() {grade := 'B'marks := 90switch marks {case 90:grade = 'A'case 80:grade = 'B'case 70, 60, 50:grade = 'C'default:grade = 'D'}switch {case grade == 'A':fmt.Println("优秀")case grade == 'B':fmt.Println("良好")case grade == 'C':fmt.Println("及格")default:fmt.Println("不及格")}fmt.Println("你的等级是:", grade)
}

在这里插入图片描述

  • switch语句还可以被用于type-switch来判断某个 interface 变量中实际存储的变量类型。

Type Switch 语法格式如下

switch x.(type){case type:statement(s);      case type:statement(s); /* 你可以定义任意个数的case */default: /* 可选 */statement(s);
}

实例:

package Switchimport "fmt"func TypeSwitch() {var x interface{}switch i := x.(type) {case nil:fmt.Printf("x的类型: %T\n", i)case int:fmt.Println("x是int型")case float64:fmt.Println("x是float64型")case func(int) float64:fmt.Println("x是func(int)型")case bool, string:fmt.Println("x是bool或string型")default:fmt.Println("未知型")}
}

在这里插入图片描述

  • fallthrough
    使用 fallthrough 会强制执行后面的 case 语句,包括defaultfallthrough 不会判断下一条case的表达式结果是否为 true。
  • fallthrough只会强制执行后面一条case语句,而不是后面的全部;

实例1:

package Switchimport "fmt"func Fallthrough() {switch {case false:fmt.Println("1.case条件语句为false")fallthroughcase true:fmt.Println("2.case条件语句为true")fallthroughcase false:fmt.Println("3.case条件语句为false")fallthroughcase true:fmt.Println("4.case条件语句为true")fallthroughcase false:fmt.Println("5.case条件语句为false")fallthroughdefault:fmt.Println("6.默认case")}
}

在这里插入图片描述
实例2:

package Switchimport "fmt"func Fallthrough() {switch {case false:fmt.Println("1.case条件语句为false")fallthroughcase true:fmt.Println("2.case条件语句为true")fallthroughcase false:fmt.Println("3.case条件语句为false")//fallthroughcase true:fmt.Println("4.case条件语句为true")//fallthroughcase false:fmt.Println("5.case条件语句为false")//fallthroughdefault:fmt.Println("6.默认case")}
}

在这里插入图片描述

3.select语句

select 是 Go 中的一个控制结构,类似于 switch 语句。

  • select 语句只能用于通道操作每个 case 必须是一个通道操作,要么是发送要么是接收。
  • select 语句会监听所有指定的通道上的操作,一旦其中一个通道准备好就会执行相应的代码块。
  • 如果多个通道都准备好,那么 select 语句会随机选择一个通道执行。如果所有通道都没有准备好,那么执行 default 块中的代码。

Go 编程语言中 select 语句的语法如下:

select {case <- channel1:// 执行的代码case value := <- channel2:// 执行的代码case channel3 <- value:// 执行的代码// 你可以定义任意数量的 casedefault:// 所有通道都没有准备好,执行的代码
}
  • 每个 case 都必须是一个通道
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通道可以进行,它就执行,其他被忽略。
  • 如果有多个 case 都可以运行,select 会随机公平地选出一个执行,其他不会执行。
    否则:
    • 如果有 default 子句,则执行该语句。
    • 如果没有 default 子句,select 将阻塞,直到某个通道 可以运行;Go 不会重新对 channel 或值进行求值。

实例1:

package Selectimport ("fmt""time"
)func Select() {c1 := make(chan string)c2 := make(chan string)go func() {time.Sleep(1 * time.Second)c1 <- "one"}()go func() {time.Sleep(2 * time.Second)c2 <- "two"}()for i := 0; i < 2; i++ {select {case msg1 := <-c1:fmt.Println("received", msg1)case msg2 := <-c2:fmt.Println("received", msg2)}}
}

在这里插入图片描述

  • 以上实例中,我们创建了两个通道 c1 和 c2。
    select 语句等待两个通道的数据。如果接收到 c1 的数据,就会打印 “received one”;如果接收到 c2 的数据,就会打印 “received two”。

实例2:

package Selectimport ("fmt""time"
)func Select1() {c1 := make(chan string)c2 := make(chan string)go func() {time.Sleep(1 * time.Second)c1 <- "one"}()go func() {time.Sleep(2 * time.Second)c2 <- "two"}()for i := 0; i < 2; i++ {select {case msg1 := <-c1:fmt.Println("received", msg1)case msg2 := <-c2:fmt.Println("received", msg2)}}
}func Select2() {// 定义两个通道ch1 := make(chan string)ch2 := make(chan string)// 启动两个 goroutine,分别从两个通道中获取数据go func() {for {ch1 <- "from 1"}}()go func() {for {ch2 <- "from 2"}}()// 使用 select 语句非阻塞地从两个通道中获取数据for {select {case msg1 := <-ch1:fmt.Println(msg1)case msg2 := <-ch2:fmt.Println(msg2)default:// 如果两个通道都没有可用的数据,则执行这里的语句fmt.Println("no message received")}}
}

在这里插入图片描述

  • 以上实例中,我们定义了两个通道,并启动了两个协程(Goroutine)从这两个通道中获取数据。在 main 函数中,我们使用 select 语句在这两个通道中进行非阻塞的选择,如果两个通道都没有可用的数据,就执行 default 子句中的语句。
    以上实例执行后会不断地从两个通道中获取到的数据,当两个通道都没有可用的数据时,会输出 “no message received”。

二、循环语句

1.for循环

for 循环是一个循环控制结构,可以执行指定次数的循环。
Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。

  • 和 C 语言的 for 一样:
for init; condition; post { }

init: 一般为赋值表达式,给控制变量赋初值;
condition: 关系表达式或逻辑表达式,循环控制条件;
post: 一般为赋值表达式,给控制变量增量或减量。

  • 和 C 的 while 一样:
for condition { }
  • 和 C 的 for(;;) 一样:
for { }
  • for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldMap {newMap[key] = value
}

以上代码中的 key 和 value 是可以省略。
如果只想读取 key,格式如下:

for key := range oldMap

或者这样:

for key, _ := range oldMap

如果只想读取 value,格式如下:

for _, value := range oldMap

实例1:

package Forimport "fmt"func For() {sum := 0for i := 1; i <= 10; i++ {sum += i}fmt.Println(sum)
}

在这里插入图片描述

实例2:

package Forimport "fmt"func While() {sum := 1for sum <= 10 {sum += sum}fmt.Println(sum)
}

在这里插入图片描述

  • 以上实例是将init 和 post参数去掉,相当于是一个while循环

实例3:

package Forimport "fmt"func main() {sum := 0for {sum++ // 无限循环下去}fmt.Println(sum) // 无法输出
}
  • for后面什么也不跟就是无限循环;

实例4:

package Forimport "fmt"func Range() {strings := []string{"google", "runoob"}for i, s := range strings {fmt.Println(i, s)}numbers := [6]int{1, 2, 3, 5}for i, x := range numbers {fmt.Printf("第 %d 位 x 的值 = %d\n", i, x)}
}

在这里插入图片描述

  • For-each range 循环可以对字符串、数组、切片等进行迭代输出元素。

实例5:

package Forimport "fmt"func Range() {map1 := make(map[int]float32)map1[1] = 1.0map1[2] = 2.0map1[3] = 3.0map1[4] = 4.0// 读取 key 和 valuefor key, value := range map1 {fmt.Printf("key is: %d - value is: %f\n", key, value)}// 读取 keyfor key := range map1 {fmt.Printf("key is: %d\n", key)}// 读取 valuefor _, value := range map1 {fmt.Printf("value is: %f\n", value)}
}

在这里插入图片描述

  • For-each range也可以读取map中的k和v

三、defer语句

1.defer语句的作用

defer语句被用于预定对一个函数的调用。可以把这类被defer语句调用的函数称为延迟函数。
defer语句会将其后的函数调用推迟到当前所在函数体的生命周期结束后再执行,类似于c++的析构函数。这个特性常用于处理成对的操作,如打开/关闭文件、获取/释放锁、连接/断开连接等确保资源被适当地释放,即使在发生错误或提前返回的情况下也能保证执行。
defer作用:

  • 释放占用的资源
  • 捕捉处理异常
  • 输出日志

如果一个函数中有多个defer语句,它们会以LIFO(后进先出)的顺序执行。
在这里插入图片描述
实例

package Deferimport "fmt"func Defer() {defer fmt.Println("main end1")defer fmt.Println("main end2")fmt.Println("0")fmt.Println("1")
}

在这里插入图片描述

  • defer语句调用的函数会在当前函数体生命周期结束后再出栈执行,多个defer语句调用函数的顺序类似于堆栈,后进先出;

2.defer和return的先后顺序

package Deferimport "fmt"func deferFunc() int {fmt.Println("defer func called...")return 0
}func returnFunc() int {fmt.Println("return func caller...")return 0
}func ReturnAndDefer() int {defer deferFunc()return returnFunc()
}

在这里插入图片描述

  • 由于defer语句会将其后的函数调用推迟到当前所在函数体的生命周期结束后再出栈,而return语句是在}之前的,因此return会先执行,defer再执行;

3.recover错误拦截

运行时panic异常一旦被引发就会导致程序崩溃。

  • Go语言提供了专用于“拦截”运行时panic的内建函数recover它可以是当前的程序从运行时panic的状态中恢复并重新获得流程控制权
  • 注意:recover只有在defer调用的函数中有效。

实例1:

package mainimport "fmt"func recoverFunc(i int) {//定义10个元素的数组var arr [10]int//错误拦截要在产生错误前设置//这里使用匿名函数进行错误拦截,在进行defer调用//相当于这个匿名函数在recoverFunc的生命周期结束后才被调用defer func() {//设置recover拦截错误信息err := recover()//产生panic异常,打印错误信息if err != nil {fmt.Println(err)}}()//根据函数参数为数组元素赋值//如果i的值超过数组下标 会报错误:数组下标越界arr[i] = 2
}func main() {recoverFunc(10)fmt.Println("程序继续执行...")
}

在这里插入图片描述

  • 在上述实例中,我们定义了一个匿名函数来拦截panic,并用defer去掉用,这个匿名函数会在当前recoverFunc的生命周期结束后进行调用,recoverFunc函数中出现了数组越界的错误,之后被recover()拦截了,程序得以继续执行;

实例2:

package mainimport "fmt"func handlePanic() {if r := recover(); r != nil {fmt.Println("Recovered:", r)}
}func performTask() {defer handlePanic()fmt.Println("Performing some task...")panic("Oops! Something went wrong!")fmt.Println("Task completed.")
}func main() {performTask()fmt.Println("Main function continues.")
}

在这里插入图片描述

  • 在以上的实例中,panic函数调用后,异常被引发,当前performTask函数执行结束,defer调用的函数开始出栈,执行handlePanic函数,panic异常引发后,在handlePanic函数中recover拦截了异常,打印出错误信息,并让main函数继续运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/340961.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

212. 单词搜索 II(字典树的另一种类型)

大致思路是&#xff1a; 根据words列表建立字典树&#xff0c;其中注意在单词末尾&#xff0c;将原来的isEnd变量换成存储这个单词的变量&#xff0c;方便存储到ans中&#xff0c;另外&#xff0c;字典树的字节点由原来的Trie数组变为hashmap&#xff0c;方便检索字母。 建立…

C++ n皇后问题 || 深度优先搜索模版题

n− 皇后问题是指将 n 个皇后放在 nn 的国际象棋棋盘上&#xff0c;使得皇后不能相互攻击到&#xff0c;即任意两个皇后都不能处于同一行、同一列或同一斜线上。 现在给定整数 n &#xff0c;请你输出所有的满足条件的棋子摆法。 输入格式 共一行&#xff0c;包含整数 n 。 …

动态规划day03

343. 整数拆分(第二次做还是没弄明白) 力扣题目链接(opens new window) 给定一个正整数 n&#xff0c;将其拆分为至少两个正整数的和&#xff0c;并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 示例 1: 输入: 2输出: 1解释: 2 1 1, 1 1 1。 示例 2: 输入: …

黑马程序员JavaWeb开发|案例:tlias智能学习辅助系统(4)员工管理|修改员工、配置文件

指路&#xff08;1&#xff09;&#xff08;2&#xff09;&#xff08;3&#xff09;&#x1f447; 黑马程序员JavaWeb开发|案例&#xff1a;tlias智能学习辅助系统&#xff08;1&#xff09;准备工作、部门管理_tlias智能学习辅助系统的需求分析-CSDN博客https://blog.csdn.n…

AI人工智能的发展趋势及未来展望

人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;作为一门拥有悠久历史但最近才得到广泛关注的领域&#xff0c;正在以惊人的速度推动着科技进步和社会变革。近年来&#xff0c;随着计算能力、数据规模和算法研究的不断突破&#xff0c;人工智能已经…

java通过HttpClient方式实现https请求的工具类(绕过证书验证)

目录 一、引入依赖包二、HttpClient方式实现的https请求工具类三、测试类 一、引入依赖包 引入相关依赖包 <!--lombok用于简化实体类开发--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><option…

MySQL批量插入技巧

关于MySQL批量插入的一些问题 MySQL一直是我们互联网行业比较常用的数据&#xff0c;当我们使用半ORM框架进行MySQL大批量插入操作时&#xff0c;你是否考虑过这些问题: 进行大数据量插入时&#xff0c;是否需要进行分批次插入&#xff0c;一次插入多少合适&#xff1f;有什么…

泡泡玛特台北旗舰店打造“乐园式体验”,打造西门町新地标

近日&#xff0c;泡泡玛特台北旗舰店盛大开业&#xff0c;矗立于西门町核心商圈的壮观五层独栋建筑吸引大量游客驻足。作为年度收官之作&#xff0c;该店总面积700多平方米&#xff0c;售卖超过千款潮玩。各楼层经过精心规划&#xff0c;除了各大IP最新款潮玩产品及衍生品之外&…

[蓝桥杯学习] 树状树组

lowbit操作 数字二进制表达中的最低位1以及后面所有的0&#xff0c;函数写法如下&#xff1a; int lowbit(int x){return x&-x;} 例如说&#xff0c;lowbit(0101100100) (100) lowbit(4) 4 lowbit(6) 2 时间复杂度o(1) 树状数组 应用 进行单点修改和区间查询…

第 378 场 LeetCode 周赛题解

A 检查按位或是否存在尾随零 枚举&#xff1a;枚举两个元素的组合即可 class Solution { public:bool hasTrailingZeros(vector<int> &nums) {int n nums.size();for (int i 0; i < n; i)for (int j 0; j < i; j)if ((nums[i] | nums[j]) % 2 0)return tru…

平面光波导_三层均匀平面光波导_射线分析法

平面光波导_三层均匀平面光波导_射线分析法 三层均匀平面光波导&#xff1a; 折射率沿 x x x 方向有变化&#xff0c;沿 y y y、 z z z 方向没有变化三层&#xff1a;芯区( n 1 n_1 n1​) > > > 衬底( n 2 n_2 n2​) ≥ \geq ≥ 包层( n 3 n_3 n3​)包层通常为空…

【排序算法】四、堆排序(C/C++)

「前言」文章内容是排序算法之堆排序的讲解。&#xff08;所有文章已经分类好&#xff0c;放心食用&#xff09; 「归属专栏」排序算法 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 堆排序1.1 原理1.2 堆的向下调整1.3 堆排序代码实现1.3 性质总结 堆排序 1.1 原理 概念介…