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")
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

海康威视综合安防管理平台 detection 前台RCE漏洞复现

0x01 产品简介 海康威视综合安防管理平台是一套“集成化”、“智能化”的平台,通过接入视频监控、一卡通、停车场、报警检测等系统的设备。海康威视集成化综合管理软件平台,可以对接入的视频监控点集中管理,实现统一部署、统一配置、统一管理和统一调度。 0x02 漏洞概述 海康…

k8s中部署nacos

1 部署nfs # 在k8s的主节点上执行 mkdir -p /appdata/download cd /appdata/download git clone https://github.com/nacos-group/nacos-k8s.git 将nacos部署到middleware的命名空间中 kubectl create namespace middleware cd /appdata/download/nacos-k8s # 创建角色 kub…

JavaScript中==和===的区别

&#x1f9d1;‍&#x1f4bb; 写在开头 点赞 收藏 学会&#x1f923;&#x1f923;&#x1f923; 前言 JavaScript 中的相等运算符无疑是新手开发者最容易混淆的知识点之一。 和这两个运算符的细微差别往往会在代码中造成一些令人困惑的行为 在本文中,我们将深入探讨这两个…

Google Chrome 浏览器在链接上点右键的快捷键

如今&#xff0c;越来越多的软件都懒得设个快捷键&#xff0c;就算设置了连个下划线也懒得加了。 谷歌浏览器右键 > 链接另存为... 和 复制链接地址 的快捷键 (如图)

Flink架构底层原理详解:案例解析(43天)

系列文章目录 一、Flink架构&#xff08;掌握&#xff09; 二、Flink代码案例&#xff08;掌握&#xff09; 三、UDF&#xff08;熟悉&#xff09; 四、Flink常见面试题整理 文章目录 系列文章目录前言一、Flink架构&#xff08;掌握&#xff09;1、系统架构1.1 通信&#xff…

SystemUI默认去掉底部导航栏

一、背景 在Android系统中&#xff0c;SystemUI负责管理系统的状态栏、导航栏等用户界面元素。若要在SystemUI中默认去掉底部导航栏&#xff0c; 可以通过以下几种方法实现&#xff1a; 1. 修改布局文件 在Android的SystemUI源代码中&#xff0c;底部导航栏的布局文件通常…

SpringBoot+Session+redis实现分布式登录

SpringBootSessionRedis实现分布式登录功能实现 文章目录 目录 文章目录 前言 一、引库 二、修改配置文件 三、使用 四、解决乱码问题 1.引库 2.配置redis序列化 3.配置Session-Redis序列化 前言 这里简单介绍一下&#xff0c;如果你想多台机器部署你的项目的话&#xff0c;在…

重大突破!OpenAI 推出 GPT-4o mini,AI 领域再掀波澜!

北京时间 7 月 18 日晚&#xff0c;OpenAI 重磅推出“小模型”GPT-4o mini&#xff0c;其在文本智能和多模态推理方面展现出卓越性能&#xff0c;超越 GPT-3.5 Turbo&#xff0c;在 LMSYS“聊天机器人对战”排行榜上也力压 GPT-4。 GPT-4o mini 支持 128K Token 的长上下文窗口…

一起学Java(1)-新建一个Gradle管理的Java项目

一时兴起&#xff0c;也为了便于跟大家同步学习进展和分享样例代码&#xff0c;遂决定创建一个全新的Java项目&#xff0c;并通过Github与大家分享。本文就是记录该项目的创建过程以及其中的一些知识要点&#xff08;如Gradle等&#xff09;。为了紧跟技术潮流和提高操作效率&a…

污染物CMAQ模型的安装

CMAQ安装教程(基于intel编译器) 简介 CMAQ&#xff08;Community Multiscale Air Quality&#xff09;系统是由美国国家环境保护局&#xff08;EPA, Environmental Protection Agency&#xff09;于1998年发布&#xff0c;是用于估算臭氧、颗粒物、有毒化合物和酸沉降等大气污…

第5讲:Sysmac Studio中的硬件拓扑

Sysmac Studio软件概述 一、创建项目 在打开的软件中选择新建工程 然后在工程属性中输入工程名称,作者,类型选择“标准工程”即可。 在选择设备处,类型选择“控制器”。 在版本处,可以在NJ控制器的硬件右侧标签处找到这样一个版本号。 我们今天用到的是1.40,所以在软…

DocRED数据集

DocRED数据集文件夹包含多个JSON文件&#xff0c;每个文件都有不同的用途。以下是这些文件的用途解释以及哪个文件是训练集&#xff1a; 文件解释 dev.json&#xff1a;包含开发集&#xff08;验证集&#xff09;的数据&#xff0c;通常用于模型调优和选择超参数。 label_map…

工业4.0与智能制造解决方案(149页PPT下载)

工业4.0&#xff0c;也被称为第四次工业革命&#xff0c;是一场将先进信息技术与制造业深度融合的全球性变革。这一概念起源于2011年德国提出的高科技战略项目&#xff0c;旨在通过利用物联网&#xff08;IoT&#xff09;、大数据、云计算、人工智能&#xff08;AI&#xff09;…

海康威视工业相机SDK+Python+PyQt开发数据采集系统(支持软件触发、编码器触发)

海康威视工业相机SDKPythonPyQt开发数据采集系统&#xff08;支持软件触发、编码器触发&#xff09; pythonpyqt开发海康相机数据采集系统 1 开发软件功能&#xff1a; 支持搜索相机&#xff1a;Gige相机设备和USB相机设备支持两种触发模式&#xff1a;软件触发和编码器触发支…

Python基础知识——(005)

文章目录 P21——20. 比较运算符 P22——21. 逻辑运算符 P23——22. 位运算和运算符的优先级 P24——23. 本章总结和章节习题 P21——20. 比较运算符 示例3-17—比较运算符的使用&#xff1a; P22——21. 逻辑运算符 示例3-18—逻辑运算符的使用&#xff1a; print(True and T…

群管机器人官网源码

一款非常好看的群管机器人html官网源码 搭建教程&#xff1a; 域名解析绑定 源码文件上传解压 访问域名即可 演示图片&#xff1a; 群管机器人官网源码下载&#xff1a;客户端下载 - 红客网络编程与渗透技术 原文链接&#xff1a; 群管机器人官网源码

Python设计模式:巧用元类创建单例模式!

✨ 内容&#xff1a; 今天我们来探讨一个高级且实用的Python概念——元类&#xff08;Metaclasses&#xff09;。元类是创建类的类&#xff0c;它们可以用来控制类的行为。通过本次练习&#xff0c;我们将学习如何使用元类来实现单例模式&#xff0c;确保某个类在整个程序中只…

如何使用大语言模型绘制专业图表

过去的一年里&#xff0c;我相信大部分人都已经看到了大语言模型(后文简称LLM)所具备的自然语言理解和文本生成的能力&#xff0c;还有很多人将其应用于日常工作中&#xff0c;比如文案写作、资料查询、代码生成……今天我要向大家介绍LLM的一种新使用方式——绘图。这里说的绘…

昇思25天学习打卡营第19天| Diffusion扩散模型

扩散模型&#xff0c;特别是Denoising Diffusion Probabilistic Models&#xff08;DDPM&#xff09;&#xff0c;是一种从纯噪声开始&#xff0c;通过逐步去噪生成数据样本的技术。它在图像、音频、视频生成上都取得了不错的成果&#xff0c;比如OpenAI的GLIDE和DALL-E 2。 扩…

three完全开源扩展案例04-阵列模型

https://www.threelab.cn/three-cesium-examples/public/index.html#/codeMirror?navigationThree.js%E6%A1%88%E4%BE%8B[r166]&classifybasic&id%E9%98%B5%E5%88%97%E6%A8%A1%E5%9E%8B 更多案例 import * as THREE from three; import { OrbitControls } from three…