Go语言流程控制

news/2024/6/20 20:55:47/文章来源:https://blog.csdn.net/weixin_57023347/article/details/137087474

        条件语句需要开发者通过指定一个或多个条件,并通过测试条件是否为true来决定是否执行指定语句,并在条件为false的情况下执行另外的语句。

        Go语言提供了一下几种条件判断语句

一. 条件语句if

        1.1 if语句由一个布尔表达式后紧跟一个或多个语句组成

        语法:

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

        特点:

  • 可省略条件表达式括号
  • 持初始化语句,可定义代码块局部变量
  • 代码左括号必须在条件表达式尾部
  • Go语言不支持三目运算符 "a > b ? a : b"
package mainimport "fmt"func main() {n := 0//报错// if n > 0// {// }if str := "abc"; n > 0 { //初始化语句 不一定是定义变量,如println("init")也可以fmt.Println(str[2])} else if n < 0 { //注意else if 和else左大括号位置fmt.Println(str[1])} else {fmt.Println(str[0])}
}

        if在布尔表达式为true时,其后紧跟的语句块执行,如果为false则不执行。 

         1.2 if ... else语句

        if语句后可以使用可选的else语句,else语句中的表达式在布尔表达式为false时执行。

        语法:

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

        实例:

        1.3 if ... else if ... else语句

        语法:

if 布尔表达式1 {/*布尔表达式1为true*/
} else if 布尔表达式2{/*布尔表达式1为false, 布尔表达式2为true*/
} else {/*布尔表达似1和布尔表达式2为false*/
}

         实例:

        1.4 if嵌套语句

        语法:

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

        实例:

二.条件语句switch 

         2.1 switch语句

        switch语句用于基于不同条件执行不同的动作,每个分支的case都是唯一的,从上往下逐一测试,直到匹配为止。

        Golang的switch分支表达式可以是任意类型,不限于常量。可省略break,默认自动终止。

        当所有的case都匹配不上,执行default里的代码。

        语法:

switch var1 {case val1:...case val2:...default:...
}

         变量var1可以是任意类型,而val1和val2可以是同类型的任意值。类型不被局限于常量或者整数,但必须是同类型,或者最终结果为相同类型的表达式。

        case中可以同时测试多个可能符合条件的值,使用逗号分隔它们。例如:case val1, val2, val3。

        实例:

         2.2 Type Switch

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

        语法:

switch x.(type) {case type1:statement1(s)case type2:statement1(s)/*你可以定义任意个数的case*/default:statementn(s)
}

        实例:

  • Go语言switch非常灵活,表达式可以不是常量或整数,执行过程从上到下,直到找到匹配的。   
  • 如果switch没有表达式,它会匹配case后值为true的
  • Go里面switch默认每个case最后带有break,匹配成功不会自动向下执行其他case,而是跳出整个switch
  • 可以使用fallthrough强制执行后面的case代码,不管匹不匹配
package mainimport "fmt"func main() {var x interface{}//写法1switch i := x.(type) { //带初始化语句case nil:fmt.Printf("x 的类型: %T\r\n", i)case int:fmt.Printf("x 的类型是int\r\n")case float64:fmt.Printf("x 的类型是float64\r\n")case func(int) float64:fmt.Printf("x 的类型是func(int)\r\n")case bool, string:fmt.Printf("x 的类型是bool或string\r\n")default:fmt.Printf("类型未知\r\n")}//写法2 没有输出var j = 0switch j {case 0:case 1:fmt.Println("1")case 2:fmt.Println("2")default:fmt.Println("def")}//写法3var k = 0switch k {case 0:fmt.Println("fallthrough")fallthroughcase 1:fmt.Println("1")case 2:fmt.Println("2")default:fmt.Println("def")}//写法4var m = 0switch m {case 0, 1:fmt.Println("1")case 2:fmt.Println("2")default:fmt.Println("def")}//写法5var n = 0switch {case n > 0 && n < 10:fmt.Println("n > 0 && n < 10")case n > 10 && n < 20:fmt.Println("n > 0 && n < 10")default:fmt.Println("def")}
}

三.条件语句select

        1.1 介绍

        select是Go的一个控制结构,类似于用于通信的switch语句,每一个case必须是一个通信操作,要么是发送,要么是接收。select随机执行一个可运行的case。如果没有case可以运行,它将堵塞,直到有case可以运行。一个默认子句应该总是可运行的。 

        语法:

  • 每一个case必须是一个通信
  • 所有channel表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通信可以进行,它就执行,其他被忽略
  • 如果有多个case可以运行,select会随机公平的选出一个执行。其它不会执行
  • 如果有default,没有case可以执行,执行default语句
  • 如果没有default语句,没有case可以执行,select将阻塞,直到某个通信可以运行,Go不会重新对channel或值进行求值。
select {
case communication clause:statement(s)
case communication clause:statement(s)
/*你可以定义任意数量的case*/default:/*可选*/statement(s)}

        实例:

  • 执行过程 

         select可以监听channel的数据流动。select的用法于switch语法非常类似,由select开始的一个新的选择块,每一个选择条件由case语句类描述。

        与switch语句可以选择任何使用相等比较的条件相比,select有比较多的限制条件,其中最大的一条限制条件就是每一个case语句必须是一个I/O操作。

select {
case <-chan1://检测有没有数据可读//如果chan1成功读取到数据,则执行该case处理语句
case chan2<-1://检测有没有可以写//如果成功向chan2写入数据,则进行该case处理语句//假如没有default,那么在以上两个条件都不成立的情况下,就会在此阻塞
//一般default不会写在里面,select中的default子句总是可以运行的,因为会很消耗CPU资源
default://如果以上都没有符合条件,那么则进行default处理流程
}

在select语句中,Go会按顺序从头到尾评估每一个发送和接收语句。

如果其中的任意一个语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用。

如果没有一条语句可以执行(即所有的通道都被阻塞),那么有两种情况:

  • 如果给出default语句,那么就会执行default的流程,然后程序会继续往下执行
  • 如果没有default语句,那么select语句将被阻塞,直到至少有一个case可以进行下去

        1.2 Golang select的使用及典型用法

基本使用:

        select是Go中的一个控制结构,类似于switch语句,用于异步IO操作。select会监听case语句中的channel的读写操作,当case中的channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作。select中的case语句必须是一个channel操作。

  • select中的default语句总是可运行的
  • 如果有多个case都可以运行,select会随机公平的选出一个执行,其它不会执行
  • 如果没有可运行的case语句,且有default语句,那么就会执行default的动作
  • 如果没有可运行的case语句,且没有default语句,select将会阻塞,直到某个case通信可以运行。

        典型用法:

  • 超时判断

        如下,使用全局变量resChan来接收response,如果时间超过3秒,resChan中还没有数据返回,则第二个case将执行。

package mainimport ("fmt""time"
)var resChan = make(chan int)func test() {select {case data := <-resChan:doData(data)case <-time.After(time.Second * 3):fmt.Println("request time out")}
}func doData(data int) {}func main() {test()
}
  • 退出

        在另外协程中,如果运行遇到非法操作或者不可处理的错误,就像shouldQuit发送数据通知程序停止运行。

package mainvar shouldQuit = make(chan struct{})func clearUp() {}
//主协程
func main() {{//loop}//out of loopselect {case <-shouldQuit:clearUp()returndefault:}//...
}close(shouldQuit)
  • 判断channel是否阻塞

        在某些情况下是存在不希望channel缓存满的需求

package mainvar ch = make(chan int, 5)func main() {data := 0select {case ch <- data:default://做相应操作,比如丢弃data s视需求而定}
}

四. 循环语句for

        1.1 三种循环方式

        Golang支持三种循环方式,包括类似while的语法。

        for循环是一个循环控制结构,可以执行指定次数的循环。

        语法:

        Go语言的for循环有3种形式,只有其中的一种使用分号。

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

执行过程:

  1. 先对表达式init赋初值
  2. 判断赋值表达式init是否满足给定condition条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行post,进入第二次循环,再判别condition,当condition的值为假,不满足条件,就终止循环。

        实例: 

package mainimport "fmt"func main() {s := "abc"for i := 0; i < len(s); i++ {fmt.Println(s[i])}n := len(s)for n > 0 {fmt.Println(s[n-1])n--}//死循环for {fmt.Println(s)}
}

         我们可以在初始化语句中计算出全部结果:

        for循环上初始化的变量,只在当前for 循环内有效。

package mainimport "fmt"func main() {//for初始化定义的值不会受已定义的同名变量影响//并且不能再for循环外使用for a := 0; a < 10; a++ {fmt.Printf("a的值为%d\n", a)}//报错//fmt.Println(a)var a, b = 0, 15for a < b {fmt.Printf("a的值为%d\n", a)a++}
}

        1.2 循环嵌套

        实例:

        使用循环嵌套来输出2到100间的素数:

package mainimport "fmt"func main() {for i := 2; i <= 100; i++ {j := 2for ; j <= (i / j); j++ { //只需要检测一半的数if i%j == 0 {break //不是素数}}if j > (i / j) {fmt.Printf("素数%d\n", i) //遍历完 说明是素数}}
}

         1.3 死循环

        如果循环中的条件永远不会为false,则会进行无限循环。

package mainimport "fmt"func main() {for {fmt.Println("这是死循环")}for true {fmt.Println("这是死循环")}
}

五. 循环语句range

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

        for循环的range格式对slice,map,数组,字符串等进行迭代循环。格式如下:

for key, value := range oldMap {newMap[key] = value
} 

         可以忽略不想要的返回值,或"_"这个特殊变量。

package mainfunc main() {s := "abc"//忽略value,支持string/array/slice/mapfor i := range s {println(s[i])}//忽略indexfor _, val := range s {println(val)}//忽略全部返回值,仅迭代for range s {}m := map[string]int{"a": 1, "b": 2}for k, v := range m {println(k, v)}
}
  •  注意

        在使用range进行遍历的时候,如果遍历的是值类型对象。首先会复制一份遍历的数据,然后键/索引和值是从复制的数据中取出来的。所以当修改原数组或者range后的值,互相不会产生影响。

        如果是引用类型(slice,map,chan等),其底层数据不会被复制,复制的只是指针,但是指针指向的底层数据一样。

        所以修改原数据,即修改了底层数据,会影响range后的值。但是修改range后的值,不会影响原数据,因为range后的值是一份拷贝。

        对引用类型range的数据范围进行修改不会影响range。

        5.1 for和for range的区别

主要是使用场景不同:

        for可以遍历数组,切片,key为整型递增的map和string。

        for range可以完成所有for可以做的事,也能做for不能做的事,包括遍历key为string类型的map,并同时获取key和value。 还可以遍历channel。

六.循环控制语句

        循环控制语句可以控制循环体语句的执行过程。循环控制语句包括break,continue,goto。

        Go语言的标签可以用来标记代码特定的位置。 

  • 三个语句都可以配合标签使用
  • 标签名区分大小写,定义后若不使用会造成编译错误
  • continue和break配合标签可用于多层循环的退出
  • goto是调整执行位置,与break,continue配合标签结果不同
  • break

        在循环中的作用是跳出循环。但是只能跳出当前循环,无法跳出多层循环。

         想跳出到指定位置,可以结合标签实现。标志位置表示要跳出的循环。

  • continue 

        在循环中的意思是当次循环后续语句不再执行,但是不会跳出循环。

        结合标志,表示要结束的单次循环的循环。标志指定的for循环,continue后的语句都不会执行。

  • goto 

        goto需要结合标志来使用,表示直接跳到对应的代码逻辑。

 

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

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

相关文章

如何在Portainer中创建Nginx服务并搭建静态站点实现公网访问本地网站

文章目录 前言1. 安装Portainer1.1 访问Portainer Web界面 2. 使用Portainer创建Nginx容器3. 将Web静态站点实现公网访问4. 配置Web站点公网访问地址4.1公网访问Web站点 5. 固定Web静态站点公网地址6. 固定公网地址访问Web静态站点 前言 Portainer是一个开源的Docker轻量级可视…

牛牛排队伍

有 n 个人排队&#xff0c;1 号排在 2 号前面&#xff0c;2 号排在 3 号前面&#xff0c;…&#xff0c;以此类推 n−1 号排在 n 号前面。在这个过程中&#xff0c;偶尔老师会把某个人叫走&#xff0c;叫走之后这个人就离开了队伍&#xff0c;假设本来 a排在 b 前面&#xff0c…

SiameseRPN原理详解(个人学习笔记)

参考资源&#xff1a; 视觉目标跟踪SiamRPNSiameseRPN详解CVPR2018视觉目标跟踪之 SiameseRPN 目录&#xff09; 1. 模型架构1.1 Siamese Network1.2 RPN 2. 模型训练2.1 损失函数2.2 端到端训练2.3 正负样本选择 3. 跟踪阶段总结 SiamRPN是在SiamFC的基础上进行改进而得到的一…

Adobe ColdFusion 任意文件读取漏洞复现(CVE-2024-20767)

0x01 产品简介 Adobe ColdFusion是美国奥多比(Adobe)公司的一套快速应用程序开发平台。该平台包括集成开发环境和脚本语言,将可扩展、改变游戏规则且可靠的产品的愿景变为现实。 0x02 漏洞概述 由于 Adobe ColdFusion 的访问控制不当,未经身份认证的远程攻击者可以构造恶…

Ubuntu20.04安装MatlabR2018a

一、安装包 安装包下载链接 提取码&#xff1a;kve2 网上相关教程很多&#xff0c;此处仅作为安装软件记录&#xff0c;方便后续软件重装&#xff0c;大家按需取用。 二、安装 1. 相关文件一览 下载并解压文件后&#xff0c;如下图所示&#xff1a; 2. 挂载镜像并安装 2…

服务器被CC攻击之后怎么办?

1.取消域名绑定取消域名绑定后Web服务器的CPU能够马上恢复正常状态&#xff0c;通过IP进行访问连接一切正常。但是不足之处也很明显&#xff0c;取消或者更改域名对于别人的访问带来了不变&#xff0c;另外&#xff0c;对于针对IP的CC攻击它是无效的&#xff0c;就算更换域名攻…

【WEEK5】 【DAY5】DML语言【中文版】

2024.3.29 Friday 目录 3.DML语言3.1.外键&#xff08;了解&#xff09;3.1.1.概念3.1.2.作用3.1.3.添加&#xff08;书写&#xff09;外键的几种方法3.1.3.1.创建表时直接在主动引用的表里写&#xff08;被引用的表的被引用的部分&#xff09;3.1.3.2.先创建表后修改表以添加…

unity 打包安卓错误汇集

Failed to find target with hash string "android-34’ in: D:Pr 他说找不到sdk34level的我用as打开后卸载又重装&#xff0c;最后解决了 我放到Plugins/Android/下面的Java代码没有被编译 这个不知道为什么。我故意把代码写的有问题&#xff0c;会报错那种&#xff…

认识docker

认识docker 1.镜像和容器2.MySQL镜像命令解读3.docker常用命令4.数据挂载&#xff08;1&#xff09;数据卷&#xff08;2&#xff09;本地目录挂载 5.自定义镜像&#xff08;1&#xff09;Dockerfile 6.容器网络互连7、参考 1.镜像和容器 当我们利用 Docker 安装应用时&#x…

面试题 之 webpack

1.说说你对webpack理解&#xff1f;解决什么问题&#xff1f; Webpack 是实现前端项目的模块化&#xff0c;用于现代 JavaScript 应用程序的静态模块打包工具&#xff0c;被webpack 直接引用的资源打包进 bunde.js的资源&#xff0c;当webpack 处理应用程序时,它会在内部构建一…

Mysql数据库:故障分析与配置优化

目录 前言 一、Mysql逻辑架构图 二、Mysql单实例常见故障 1、无法通过套接字连接到本地MySQL服务器 2、用户rootlocalhost访问被拒绝 3、远程连接数据库时连接很慢 4、无法打开以MYI结尾的索引文件 5、超出最大连接错误数量限制 6、连接过多 7、配置文件/etc/my.cnf权…

SmartChart的部署以及可能遇见的报错解决方案

简介 数据可视化是一种将数据转化为图形的技术&#xff0c;可以帮助人们更好地理解和分析数据。但是&#xff0c;传统的数据可视化开发往往需要编写大量的代码&#xff0c;或者使用复杂的拖拽工具&#xff0c;不仅耗时耗力&#xff0c;而且难以实现个性化的需求。有没有一种更…

《VMamba》论文笔记

原文链接&#xff1a; [2401.10166] VMamba: Visual State Space Model (arxiv.org) 原文笔记&#xff1a; What&#xff1a; VMamba: Visual State Space Model Why&#xff1a; 多年以来CNN和VIT作为视觉特征提取的主流框架 CNN具有模型简单&#xff0c;共享权重&…

The Google File System [SOSP‘03] 论文阅读笔记

原论文&#xff1a;The Google File System 1. Introduction 组件故障是常态而非例外 因此&#xff0c;我们需要持续监控、错误检测、容错和自动恢复&#xff01; 按照传统标准&#xff0c;文件数量巨大大多数文件都是通过添加新数据而不是覆盖现有数据来改变的&#xff0c;因…

近屿智能独家发布行业领先的AIGC学习路径图

近日来“人工智能即将取代大量人类工作”的话题愈演愈烈&#xff0c;在CCTV-13的《两会你我他》访谈节目中&#xff0c;众多专家也围绕这一议题展开了深入的讨论&#xff0c;AI不会取代你的工作&#xff0c;会取代你的是懂AI技术的人。李强总理在访谈中也强调了推动"人工智…

加密/ 解密 PDF:使用Python为PDF文档设置、移除密码

在数字化时代&#xff0c;文档的安全性变得越来越重要。特别是对于包含敏感信息的PDF文件&#xff0c;确保其不被未经授权的人员访问或修改是至关重要的。本文将介绍如何使用Python在PDF文档中设置密码&#xff0c;以及如何移除已经设置的密码。 目录 PDF加密基础知识 Pytho…

利用 docker 实现JMeter分布式压测

为什么需要分布式&#xff1f; 在工作中经常需要对一些关键接口做高QPS的压测&#xff0c;JMeter是由Java 语言开发&#xff0c;没创建一个线程&#xff08;虚拟用户&#xff09;&#xff0c;JVM默认会为每个线程分配1M的堆栈内存空间。受限于单台试压机的配置很难实现太高的并…

如何使用命令行对RK开发板进行OpenHarmony版本烧录?

问题 在 OpenHarmony 自动化测试环境中&#xff0c;需要对流水线上的 RK 设备进行烧录&#xff0c;图形工具只能人工操作&#xff0c;那么有什么方法可以纯命令行进行自动化烧录呢&#xff1f; 思路 我们发现 RK 开发板实际是使用 upgrade_tool 的执行文件进行烧录的&#x…

《QT实用小工具·八》数据库通用翻页类

1、概述 源码放在文章末尾 该项目实现数据库通用翻页类&#xff0c;主要包含如下功能&#xff1a; 1:自动按照设定的每页多少行数据分页 2:只需要传入表名/字段集合/每页行数/翻页指示按钮/文字指示标签 3:提供公共静态方法绑定字段数据到下拉框 4:建议条件字段用数字类型的主…

Android客户端自动化UI自动化airtest从0到1搭建macos+脚本设计demo演示+全网最全最详细保姆级有步骤有图

iOS客户端自动化UI自动化airtest从0到1搭建macosdemo演示-CSDN博客 一、基础环境 1. 安装jdk 选择jdk8 如果下载高版本 可能不匹配会失败 下载.dmg文件 苹果电脑 &#xff5c; macOS &#xff5c; jdk1.8 &#xff5c; 环境变量配置_jdk1.8 mac-CSDN博客 Java Downloads …