当前位置: 首页 > news >正文

Go基础编程 - 12 -流程控制

流程控制

  • 1. 条件语句
    • 1.1. if...else 语句
    • 1.2. switch 语句
    • 1.3. select 语句
      • 1.3.1. select 语句的通信表达式
      • 1.3.2. select 的基特性
      • 1.3.3. select 的实现原理
      • 1.3.4. 经典用法
        • 1.3.4.1 超时控制
        • 1.3.4.2 多任务并发控制
        • 1.3.4.3 监听多通道消息
        • 1.3.4.4 default 实现非堵塞读写
  • 2. 循环语句
    • 2.1. for 语句
    • 2.2. for ... range
  • 3. goto、break、continue

上一篇:函数
下一篇:单元测试


1. 条件语句

Go语言中,条件语句分为三种:if语句、switch语句和select语句。

1.1. if…else 语句

if语句基本格式如下:

if 条件 {// 条件满足时执行的语句
} else if 条件 {// 条件满足时执行的语句
} else {// 条件为false时执行的语句
}

不支持三元操作符(三目运算符) :“a > b ? a : b”

1.2. switch 语句

基于不同的条件执行不同的动作,每个case分支都是唯一的,从上至下逐一匹配,直到匹配到一个case分支,执行该分支的代码,并终止匹配。

switch语句基本格式如下:

switch{
case1:// 值等于值1时执行的语句
case2:// 值等于值2时执行的语句
default:// 值不等于值1和值2时执行的语句
}
  • 如果switch没有表达式,它会匹配true。
  • case 分支表达式可以是任意类型,不限于常量,但必须是相同类型
  • 一个 case 可以同时测试多个值,用逗号分隔。例如:case val1, val2, val3:
  • 一个 case 分支可以使用fallthrough语句,匹配成功后强制执行相邻的下一个case语句,且fallthrough不可使用在最后一个分支。
  • Go语言的switch默认相当于每个case最后带有break,可省略。

示例:

package mainimport "fmt"func main() {var i = 0switch i {case 0:println("0")    println("fallthrough")  // 使用fallthrough语句,匹配成功后强制执行下一个case代码:case 1,2fallthroughcase 1, 2:  // 一个 case 可以同时测试多个值,用逗号分隔。fmt.Println("1 或 2")case 3:fmt.Println("3")default:fmt.Println("default")// fallthrough  // fallthrough不可使用在最后一个分支}// 输出结果:// 0// fallthrough// 1 或 2var n = 6switch { //省略条件表达式默认为true,可当 if...else if...elsecase n > 0 && n < 10:fmt.Println("i > 0 and i < 10")case n > 10 && n < 20:fmt.Println("i > 10 and i < 20")default:fmt.Println("def")}// 输出结果:// i > 0 and i < 10
}

1.3. select 语句

select是Go中的一个控制结构,类似 switch 语句,用于处理异步IO操作。但是select用于等待多个通信操作的完成,会随机执行一个可运行的case;如果没有case可运行,它将阻塞,直到有case可运行。

1.3.1. select 语句的通信表达式

  • 一个通信操作,如:ch <- vv := <-ch
  • 一个接收表达式,如:v := <-ch
  • 一个发送表达式,如:ch <- v
  • 一个默认通信,如:default

1.3.2. select 的基特性

  • case 语句必须是一个 cannel 操作,要么是发送,要么是接收。
  • select 中 default 语句总是可执行的(一般不写在里面,因为会很消CPU资源)。
  • 如果任意某个通信可以执行,它就执行;其它被忽略。
  • 如果有多个 case 都可以运行,select 会随机公平地选出一个执行;其它不会执行。
  • 如果没有可运行的 case 语句,且有 default 语句,那么就会执行 default 的动作。
  • 如果没有可运行的 case 语句,且没有 default 语句,select 将阻塞,直到某个 case 通信可以运行。

1.3.3. select 的实现原理

参考:Go select 底层原理、select 的随机公平策略理

在这里插入图片描述

无 case 永久堵塞

select{} // fatal error: all goroutines are asleep - deadlock!
// 
// goroutine 1 [select (no cases)]:

select 所有 case 均无法执行且没有 default,则阻塞

ch := make(chan struct{})
select {
case data <- ch:  // 只有一个 case,实际会被编译器转换为相应 channel 相应的收发操作,其实和实际调用 data := <- ch 并没有什么区别fmt.Printf("ch data: %v\n", data)
}// fatal error: all goroutines are asleep - deadlock!
// 
// goroutine 1 [chan receive]:

select多个case同时可以执行,随机选择一个去执行

package mainimport "fmt"func main() {var c1 = make(chan int, 2)c2 := make(chan string, 2)c3 := make(chan int, 2)var i1 inti2 := "two"c1 <- 1c2 <- "one"c3 <- 3select {case i1 = <-c1:fmt.Printf("received %d from c1\n", i1)case c2 <- i2:fmt.Printf("send %s to c2\n", i2)case i3, ok := <-c3: // same as: i3, ok := (<-c3)if ok {fmt.Printf("received %d from c3\n", i3)} else {fmt.Printf("c3 is closed\n")}default:fmt.Printf("no communication\n")}
}
//随机输出下面一条:
// send two to c2
// received 1 from c1
// received 3 from c3

1.3.4. 经典用法

1.3.4.1 超时控制
package mainimport ("fmt""time"
)func main() {ch := make(chan int)go func() {time.Sleep(3 * time.Second)ch <- 1}()select {case data, ok := <-ch:if ok {fmt.Println("接收到数据: ", data)} else {fmt.Println("通道已被关闭")}case <-time.After(2 * time.Second):fmt.Println("超时了!")}
}// 超时了!
1.3.4.2 多任务并发控制
package mainimport ("fmt"
)func main() {ch := make(chan int)for i := 0; i < 10; i++ {go func(id int) {ch <- id}(i)}for i := 0; i < 10; i++ {select {case data, ok := <-ch:if ok {fmt.Println("任务完成:", data)} else {fmt.Println("通道已被关闭")}}}
}// 每次执行,顺序不一致
// 任务完成: 2
// 任务完成: 0
// 任务完成: 1
// 任务完成: 4
// 任务完成: 3
// 任务完成: 6
// 任务完成: 5
// 任务完成: 7
// 任务完成: 8
// 任务完成: 9
1.3.4.3 监听多通道消息
package mainimport ("fmt""time"
)func main() {ch1 := make(chan int)ch2 := make(chan int)// 开启 goroutine 1 用于向通道 ch1 发送数据go func() {for i := 0; i < 5; i++ {ch1 <- itime.Sleep(time.Second)}}()// 开启 goroutine 2 用于向通道 ch2 发送数据go func() {for i := 5; i < 10; i++ {ch2 <- itime.Sleep(time.Second)}}()// 主 goroutine 从 ch1 和 ch2 中接收数据并打印for i := 0; i < 10; i++ {select {case data := <-ch1:fmt.Println("Received from ch1:", data)case data := <-ch2:fmt.Println("Received from ch2:", data)}}fmt.Println("Done.")
}
1.3.4.4 default 实现非堵塞读写
import ("fmt""time"
)func main() {ch := make(chan int, 1)go func() {for i := 1; i <= 5; i++ {ch <- itime.Sleep(1 * time.Second)}close(ch)}()for {select {case val, ok := <-ch:if ok {fmt.Println(val)} else {ch = nil}default:fmt.Println("No value ready")time.Sleep(500 * time.Millisecond)}if ch == nil {break}}
}

2. 循环语句

2.1. for 语句

Go语言 for 循环有 3 种形式。

for init; condition; post{}
for condition {}
for {}

示例:

package mainimport "fmt"func main() {for i := 0; i < 10; i++ {fmt.Println("i =", i)}fmt.Println()n := 10for n > 0 {fmt.Println("n =", n)n--}fmt.Println()j := 0for {if j >= 10 {break}fmt.Println("j =", j)j++}fmt.Println()
}

2.2. for … range

range 类似迭代器操作,返回(索引, 值)或(键, 值)。

for ... range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:

for key, value := range oldMap {}

示例:

package mainimport "fmt"func main() {s := "string中文"for i, v := range s {fmt.Printf("%d, %d, %T\n", i, v, v)}println()// 忽略值for i := range s {fmt.Printf("%d\n", i)}// 忽略返回值,仅迭代for range s {}println()println()a := [3]int{0, 1, 2}for i, v := range a {if i == 0 {a[1], a[2] = 222, 333 // range 会复制对象,修改 a 不影响 i, v 的值}fmt.Println(i, v, a) // 输出:[0 222 333]a[i] = 100 + v}fmt.Println(a) // 输出:[100 101 102]println()println()si := []int{1, 2, 3, 4, 5}for i, v := range si {if i == 0 {si = si[:3] // 对 slice 的修改,不会影响 rangesi[2] = 100 // 对底层数据的修改,影响 range}fmt.Printf("%d, %d, %v\n", i, v, si)}
}

for...range 可以遍历 channel, 与遍历 map、slice 不同

package mainimport "fmt"func main() {queue := make(chan string, 2)for i := 0; i < 10; i++ {queue <- "-data-" + strconv.Itoa(i)}close(queue)// 这个 `range` 迭代从 `queue` 中得到的每个值。// 因为我们在前面 `close` 了这个通道,这个迭代会在接收完 queue 中的值之后结束;for elem := range queue {fmt.Println(elem)}// 如果我们没有 `close` 它,我们将在这个循环中继续阻塞执行,等待接收下一个个值。类似下面代码 for {}for {fmt.Println(<- queue)}
}

3. goto、break、continue

break:跳出循环。
continue:跳过当前循环,继续下一次循环。仅限 for 循环内使用。
goto:通过label跳转到指定位置。

  • 三个标签都可以配合标签(label)使用。
  • continue, break 配合标签可用于多层循环跳出。
  • goto 是调整执行位置,跳到指定标签代码块执行;continue 配合标签为跳到指定循环继续执行, break 配合标签跳出指定标签代码块的循环。
package mainimport "Learing/demo"func main() {// 标签区名分大小写,若定义标签不使用则会照成编译错误。
LabelBreak: // break 的跳转标签放在循环语句前面for {for i := 0; i < 10; i++ {if i > 2 {break LabelBreak // break, 跳出 LabelBreak 标签代码块,不再执行循环}fmt.Println("break -", i)}}fmt.Println()LableContinue:  // continue 的跳转标签放在循环语句前面for i := 0; i < 5; i++ {for {fmt.Println("before", i)continue LableContinue // continue, 跳到LableContinue标签的循环,继续执行循环。fmt.Println("after")}}fmt.Println("continue label")fmt.Println()for {for i := 0; i < 10; i++ {if i > 2 {goto LabelGoto // goto, 跳转到指定标签代码块}fmt.Println("goto -", i)}}
LabelGoto:fmt.Println("goto label")fmt.Println()
}func SelectBreak() {ch := make(chan int, 2)go func() {for i := 0; i < 10; i++ {ch <- i}}()Label:for {select {case v, ok := <-ch:fmt.Println(ok, v)if v == 5 {break Label // 在 for 的 select 体中 break 到外层循环}default:fmt.Println("The ch value is not ready.")time.Sleep(500 * time.Millisecond)}}fmt.Println("Break for select")
}

相关文章:

Go基础编程 - 12 -流程控制

流程控制 1. 条件语句1.1. if...else 语句1.2. switch 语句1.3. select 语句1.3.1. select 语句的通信表达式1.3.2. select 的基特性1.3.3. select 的实现原理1.3.4. 经典用法1.3.4.1 超时控制1.3.4.2 多任务并发控制1.3.4.3 监听多通道消息1.3.4.4 default 实现非堵塞读写 2. …...

汽车信息安全--TLS,OpenSSL

目录 TLS相关知识 加密技术 对称加密 非对称加密 数字签名和CA 信任链 根身份证和自签名 双方TLS认证 加密和解密的性能 TLS相关知识 加密技术 TLS依赖两种加密技术 1. 对称加密&#xff08;symmetric encryption&#xff09; 2. 非对称加密&#xff08;asymmetri…...

深入探索 SQL 中的 LIKE 右模糊匹配(LIKE RIGHT)与左模糊匹配(LIKE LEFT)

引言 在数据库操作中&#xff0c;LIKE 子句是执行模糊搜索的强大工具&#xff0c;用于匹配列中的数据与指定的模式。本文将详细介绍 LIKE 子句中的两种常用模式&#xff1a;右模糊匹配&#xff08;LIKE RIGHT&#xff09;和左模糊匹配&#xff08;LIKE LEFT&#xff09;&#…...

mybatis 多数据源 TDataSource required a single bean, but 2 were found

情况说明&#xff1a; 项目中本来就有一个数据源了&#xff0c;运行的好好的后来又合并了另一个项目&#xff0c;另一个项目也配置了数据源。 于是出现了如下错误&#xff1a; mybatis 多数据源 TDataSource required a single bean, but 2 were found 解决方法&#xff1a…...

Dubbo SPI 之路由器

1. 背景介绍 Dubbo 是一个高性能的 Java RPC 框架&#xff0c;由阿里巴巴开源并广泛应用于分布式系统中。在 Dubbo 的架构中&#xff0c;SPI&#xff08;Service Provider Interface&#xff09;是一个关键组件&#xff0c;允许在运行时动态加载不同的服务实现。SPI 机制提供了…...

Python深度学习环境配置(Pytorch、CUDA、cuDNN),包括Anaconda搭配Pycharm的环境搭建以及基础使用教程(保姆级教程,适合小白、深度学习零基础入门)

全流程导览 一、前言二、基本介绍2.1全过程软件基本介绍2.1.1 Pytorch2.1.2 Anaconda2.1.3 Pycharm2.1.4 显卡GPU及其相关概念2.1.5 CUDA和cuDNN 2.2 各部分相互间的联系和安装逻辑关系 三、Anaconda安装3.1安装Anaconda3.2配置环境变量3.3检验是否安装成功 四、Pycharm安装五、…...

月影护眼大路灯怎么样?书客|月影|霍尼韦尔超硬核实力性能测评pk!

月影护眼大路灯怎么样&#xff1f;选到专业优质的护眼大路灯是真的可以使我们在用眼时减少疲劳感&#xff0c;达到护眼效果&#xff0c;但如果不慎买到劣质的护眼灯产品&#xff0c;不仅达不到健康的环境光&#xff0c;还越用越觉得眼睛疲劳感加重&#xff0c;在水深的护眼灯市…...

邮件安全篇:邮件传输加密(SSL/TLS or STATRTTLS)

1. 前言 使用过邮件客户端的同学一定见过下面这张图。这是客户端账号配置界面&#xff0c;里面有SSL、STARTTLS选项。刚接触邮件客户端的同学肯定会有这些疑问&#xff1a;什么是SSL&#xff1f;什么是STARTTLS&#xff1f;两者有什么区别&#xff1f;具体该如何选择呢&#x…...

【系统架构设计 每日一问】三 Redis支持事务么,Redis的事务如何保证

实际上&#xff0c;关于Redis事务的说法“Redis 的事务只能保证隔离性和一致性&#xff08;I 和 C&#xff09;&#xff0c;无法保证原子性和持久性&#xff08;A 和 D&#xff09;”并不完全准确。下面我将分别解释Redis事务的四个特性&#xff1a;原子性&#xff08;Atomicit…...

【中项】系统集成项目管理工程师-第4章 信息系统架构-4.3应用架构

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…...

DasViewer打开Revit输出的fbx格式的模型,为啥一团黑?

答:这个应该是没有读取到贴图文件。贴图文件和obj文件需要在同级目录下面。 DasViewer是由大势智慧自主研发的免费的实景三维模型浏览器,采用多细节层次模型逐步自适应加载技术,让用户在极低的电脑配置下,也能流畅的加载较大规模实景三维模型,提供方便快捷的数据浏览操作。 免…...

【05】LLaMA-Factory微调大模型——初尝微调模型

上文【04】LLaMA-Factory微调大模型——数据准备介绍了如何准备指令监督微调数据&#xff0c;为后续的微调模型提供高质量、格式规范的数据支撑。本文将正式进入模型微调阶段&#xff0c;构建法律垂直应用大模型。 一、硬件依赖 LLaMA-Factory框架对硬件和软件的依赖可见以下…...

Training for Stable Diffusion

1.Training for Stable Diffusion 笔记来源&#xff1a; 1.Denoising Diffusion Probabilistic Models 2.最大似然估计(Maximum likelihood estimation) 3.Understanding Maximum Likelihood Estimation 4.How to Solve ‘CUDA out of memory’ in PyTorch 5.pytorch-stable-d…...

初学51单片机之指针基础与串口通信应用

开始之前推荐一个电路学习软件&#xff0c;这个软件笔者也刚接触。名字是Circuit有在线版本和不在线版本&#xff0c;这是笔者在B站看视频翻到的。 Paul Falstadhttps://www.falstad.com/这是地址。 离线版本在网站内点这个进去 根据你的系统下载你需要的版本红线的是windows…...

【启明智显分享】甲醛检测仪HMI方案:ESP32-S3方案4.3寸触摸串口屏,RS485、WIFI/蓝牙可选

今年&#xff0c;“串串房”一词频繁引发广大网友关注。“串串房”&#xff0c;也被称为“陷阱房”“贩子房”——炒房客以低价收购旧房子或者毛坯房&#xff0c;用极度节省成本的方式对房子进行装修&#xff0c;之后作为精修房高价租售&#xff0c;因甲醛等有害物质含量极高&a…...

Linux 驱动学习笔记

1、驱动程序分为几类&#xff1f; • 内核驱动程序&#xff08;Kernel Drivers&#xff09;&#xff1a;这些是运行在操作系统内核空间的驱动程序&#xff0c;用于直接访问和控制硬件设备。它们提供了与硬件交互的底层功能&#xff0c;如处理中断、访问寄存器、数据传输等。 •…...

ip地址设置了重启又改变了怎么回事

在数字世界的浩瀚星海中&#xff0c;IP地址就如同每个设备的“身份证”&#xff0c;确保它们在网络中准确无误地定位与通信。然而&#xff0c;当我们精心为设备配置好IP地址后&#xff0c;却时常遭遇一个令人费解的现象&#xff1a;一旦设备重启&#xff0c;原本设定的IP地址竟…...

layui table 浮动操作内容收缩,展开

layui table 隐藏浮动操作内容 fixed: right, style:, title: 操作,align:left, minWidth: 450, toolbar:#id分析&#xff1a; 浮动一块新增一个class layui-table-fixed-r 可以隐藏整块内容进行&#xff0c;新增一个按钮点击时间&#xff0c;然后进行收缩和展开 $(‘.layui-…...

Ubuntu24.04 NFS 服务配置

1、NFS 介绍 NFS 是 Network FileSystem 的缩写&#xff0c;顾名思义就是网络文件存储系统&#xff0c;它允许网络中的计算机之间通过 TCP/IP 网络共享资源。通过 NFS&#xff0c;我们本地 NFS 的客户端应用可以透明地读写位于服务端 NFS 服务器上的文件&#xff0c;就像访问本…...

vue3使用html2canvas

安装 yarn add html2canvas 代码 <template><div class"container" ref"container"><div class"left"><img :src"logo" alt"" class"logo"><h2>Contractors pass/承包商通行证&l…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...