【golang】for语句和switch语句
使用携带range子句的for语句时需要注意哪些细节?
numbers1 := []int{1, 2, 3, 4, 5, 6}
for i := range numbers1 {if i == 3 {numbers1[i] |= i}
}
fmt.Println(numbers1)
这段代码执行后会打印出什么内容?
答案:[1 2 3 7 5 6]
当for语句被执行的时候,在range关键字右边的numbers1会先被求值。
这个位置上的代码被称为range表达式。range表达式的结果值可以是数组、数组的指针、切片、字符串、字典或者允许接收操作的通道中的某一个,并且结果值只能有一个。
对于不同种类的range表达式结果值,for语句的迭代变量的数量可以有所不同。
就拿我们这里的numbers1来说,它是一个切片,那么迭代变量就可以有两个,右边的迭代变量代表当次迭代对应的某一个元素值,而左边的迭代变量则代表该元素值在切片中的索引值。
稍稍修改一下上面的代码
numbers2 := [...]int{1, 2, 3, 4, 5, 6}
maxIndex2 := len(numbers2) - 1
for i, e := range numbers2 {if i == maxIndex2 {numbers2[0] += e} else {numbers2[i+1] += e}
}
fmt.Println(numbers2)
打印的内容会是什么?
答案:[7 3 5 7 9 11]
需要注意两点:
- range表达式只会在for语句开始执行时被求值一次,无论后边会有多少次迭代;
- range表达式的求值结果会被复制,也就是说,被迭代的对象是range表达式结果值的
副本而不是原值。
基于这两个规则,我们接着往下看。在第一次迭代时,我改变的是numbers2的第二个元素的值,新值为3,也就是1和2之和。
但是,被迭代的对象的第二个元素却没有任何改变,毕竟它与numbers2已经是毫不相关的两个数组了。因此,在第二次迭代时,我会把numbers2的第三个元素的值修改为5,即被迭代对象的第二个元素值2和第三个元素值3的和。
以此类推,之后的numbers2的元素值依次会是7、9和11。当迭代到最后一个元素时,我会把numbers2的第一个元素的值修改为1和6之和。
我们再次修改代码
numbers3 := []int{1, 2, 3, 4, 5, 6}maxIndex3 := len(numbers2) - 1for i, e := range numbers3 {if i == maxIndex3 {numbers3[0] += e} else {numbers3[i+1] += e}}fmt.Println(numbers3)
把numbers2的值由一个数组改成一个切片,其中的元素值都不变。为了避免混淆,把这个切片值赋给变量numbers3,并且把后边代码中所有的numbers2都改为numbers3。
执行这段代码后打印的内容会是什么呢?
答案:[22 3 6 10 15 21]
切片与数组是不同的,切片是引用类型的,而数组是值类型的,所以上述第二段和第三段代码的结果是不同的,具体原因之前文章有提到–数组和切片底层原理。
switch语句中的switch表达式和case表达式之间有着怎样的联系?
先看一段代码:
value1 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch 1 + 3 {
case value1[0], value1[1]:fmt.Println("0 or 1")
case value1[2], value1[3]:fmt.Println("2 or 3")
case value1[4], value1[5], value1[6]:fmt.Println("4 or 5 or 6")
}
case表达式一般由case关键字和一个表达式列表组成,表达式列表中的多个表达式之间需要有英文逗号,分割,比如,上面代码中的case value1[0], value1[1]就是一个case表达式,其中的两个子表达式都是由索引表达式表示的。
在这里的每个case子句中的那些打印语句,会分别打印出不同的内容,这些内容用于表示case子句被选中的原因,比如,打印内容0 or 1表示当前case子句被选中是因为switch表达式的结果值等于0或1中的某一个。
拥有这样三个case表达式的switch语句可以成功通过编译吗?如果不可以,原因是什么?如果可以,那么该switch语句被执行后会打印出什么内容。
switch语句对switch表达式的结果类型,以及各个case表达式中子表达式的结果类型都是有要求的。毕竟,在 Go 语言中,只有类型相同的值之间才有可能被允许进行判等操作。
如果switch表达式的结果值是无类型的常量,比如1 + 3的求值结果就是无类型的常量4,那么这个常量会被自动地转换为此种常量的默认类型的值,比如整数4的默认类型是int,又比如浮点数3.14的默认类型是float64。
因此,由于上述代码中的switch表达式的结果类型是int,而那些case表达式中子表达式的结果类型却是int8,它们的类型并不相同,所以这条switch语句是无法通过编译的。
再来看一段很类似的代码:
value2 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch value2[4] {
case 0, 1:fmt.Println("0 or 1")
case 2, 3:fmt.Println("2 or 3")
case 4, 5, 6:fmt.Println("4 or 5 or 6")
}
switch表达式的结果值是int8类型的,而那些case表达式中子表达式的结果值却是无类型的常量了。这与之前的情况恰恰相反。那么,这样的switch语句可以通过编译吗?
答案是肯定的。因为,如果case表达式中子表达式的结果值是无类型的常量,那么它的类型会被自动地转换为switch表达式的结果类型,又由于上述那几个整数都可以被转换为int8类型的值,所以对这些表达式的结果值进行判等操作是没有问题的。
当然了,如果这里说的自动转换没能成功,那么switch语句照样通不过编译。

由于需要进行判等操作,所以switch表达式和case表达式的子表达式的结果类型需要相同。
switch语句会进行有限的类型转换,但肯定不能保证这种转换可以统一它们的类型。还要注意,如果这些表达式的结果类型有某个接口类型,那么一定要小心检查它们的动态值是否都具有可比性(或者说是否允许判等操作)。
switch语句对它的case表达式有哪些约束?
switch语句在case子句的选择上是具有唯一性的。
正因为如此,switch语句不允许case表达式中的子表达式结果值存在相等的情况,不论这些结果值相等的子表达式,是否存在于不同的case表达式中,都会是这样的结果。具体请看这段代码:
value3 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch value3[4] {case 0, 1, 2:fmt.Println("0 or 1 or 2")case 2, 3, 4:fmt.Println("2 or 3 or 4")case 4, 5, 6:fmt.Println("4 or 5 or 6")
}
由于在这三个case表达式中存在结果值相等的子表达式,所以这个switch语句无法通过编译。不过,好在这个约束本身还有个约束,那就是只针对结果值为常量的子表达式。
比如,子表达式1+1和2不能同时出现,1+3和4也不能同时出现。有了这个约束的约束,我们就可以想办法绕过这个对子表达式的限制了。再看一段代码:
value5 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch value5[4] {case value5[0], value5[1], value5[2]:fmt.Println("0 or 1 or 2")case value5[2], value5[3], value5[4]:fmt.Println("2 or 3 or 4")case value5[4], value5[5], value5[6]:fmt.Println("4 or 5 or 6")
}
变量名换成了value5,但这不是重点。重点是,我把case表达式中的常量都换成了诸如value5[0]这样的索引表达式。
虽然第一个case表达式和第二个case表达式都包含了value5[2],并且第二个case表达式和第三个case表达式都包含了value5[4],但这已经不是问题了。这条switch语句可以成功通过编译。
不过,这种绕过方式对用于类型判断的switch语句(以下简称为类型switch语句)就无效了。因为类型switch语句中的case表达式的子表达式,都必须直接由类型字面量表示,而无法通过间接的方式表示。代码如下:
value6 := interface{}(byte(127))
switch t := value6.(type) {
case uint8, uint16:fmt.Println("uint8 or uint16")case byte:fmt.Printf("byte")
default:fmt.Printf("unsupported type: %T", t)
}
量value6的值是空接口类型的。该值包装了一个byte类型的值127。在后面使用类型switch语句来判断value6的实际类型,并打印相应的内容。
这里有两个普通的case子句,还有一个default case子句。前者的case表达式分别是case uint8, uint16和case byte。你还记得吗?byte类型是uint8类型的别名类型。
因此,它们两个本质上是同一个类型,只是类型名称不同罢了。在这种情况下,这个类型switch语句是无法通过编译的,因为子表达式byte和uint8重复了。
文章学习自郝林老师的《Go语言36讲》
相关文章:
【golang】for语句和switch语句
使用携带range子句的for语句时需要注意哪些细节? numbers1 : []int{1, 2, 3, 4, 5, 6} for i : range numbers1 {if i 3 {numbers1[i] | i} } fmt.Println(numbers1)这段代码执行后会打印出什么内容? 答案:[1 2 3 7 5 6] 当for语句被执行…...
三、数据库索引
1、索引介绍 索引是一种用于快速查询和检索数据的数据结构,其本质可以看成是一种排序好的数据结构。 常见的索引结构有:B数,B树,Hash和红黑树等。在MySQL中,无论是 InnoDB还是MyISAM,都使用了B树作为索引…...
长时间带什么耳机最舒服,分享长时间佩戴舒服的耳机推荐
时代在进步,科技在不断革新。近年来,一种崭新的耳机——骨传导耳机,如火如荼地进驻耳机市场,引起一阵热潮。不论是平日里的工作出勤还是运动时的挥洒汗水,相比传统耳机,骨传导耳机无疑更加贴合现代生活的需…...
Yolov8小目标检测(1)
💡💡💡本文目标:通过原始基于yolov8的红外弱小目标检测,训练得到初版模型,进行问题点分析; 💡💡💡Yolo小目标检测,独家首发创新(原创),适用于Yolov5、Yolov7、Yolov8等各个Yolo系列,专栏文章提供每一步步骤和源码,带你轻松实现小目标检测涨点 💡💡…...
GPS定位漂移问题分析
有很多种因素会影响到GPS的准确率,以下是一个GPS误差引入简表: l 卫星时钟误差:0-1.5米 l 卫星轨道误差:1-5米 l 电离层引入的误差:0-30米 l 大气层引入的误差:0-30米 l 接收机…...
前端简介(HTML+CSS+JS)
学习Django过程中遇到一些前端相关的内容,于是整理了一下相关概念。 前端开发是创建WEB页面或APP等前端界面呈现给用户的过程。 如果只是想要入门前端,只要学习网页三剑客(HTML、CSS、JavaScript)即可。 如果把网页比喻成一个房子,HTML就是…...
List与String数组互转
一.List 转为 String 数组 1.使用toArray方法 public static void main(String[] args) {List<String> list Lists.newArrayList("1","2","3");// Java6以前版本String[] str1 list.toArray(new String[list.size()]);// Java6以后版本…...
MySQL中的数据类型
文章目录 1 常见的数据类型2 整数类型2.1 属性 M2.2 属性 UNSIGNED2.3 属性 ZEROFILL2.4 整数类型的适用场景 3 浮点类型4 定点类型5 位类型6 日期与时间类型6.1 YEAR 类型6.2 DATE 类型6.3 TIME 类型6.4 DATETIME 类型6.5 TIMESTAMP 类型 1 常见的数据类型 类型类型分类整数类…...
python多任务
一、多任务 1.1 概念 多任务就是指:同一时间能执行多个任务。比方我们的电脑能一边QQ聊天,一边写论文,还能听歌。 1.2 多任务的优势: 多任务的最大好处是 充分利用CPU资源,提高程序的执行效率。 1.3 多任务的两种表…...
c语言 - inline关键字(内联函数)
概念 在编程中,inline是一个关键字,用于修饰函数。inline函数是一种对编译器的提示,表示这个函数在编译时应该进行内联展开。 内联展开是指将函数的代码插入到调用该函数的地方,而不是通过函数调用的方式执行。这样可以减少函数调…...
如何在Ubuntu 18.04上安装PHP 7.4并搭建本地开发环境
引言 PHP是一种流行的服务器脚本语言,用于创建动态和交互式web页面。开始使用你选择的语言是学习编程的第一步。 本教程将指导您在Ubuntu上安装PHP 7.4,并通过命令行设置本地编程环境。您还将安装依赖管理器Composer,并通过运行脚本来测试您…...
狭义相对论
文章目录 一、为什么光速不变?二、为什么爱因斯坦坚信“相对性原理”三、逻辑和数学显威力,狭义相对论时空变换(洛伦兹变换)推导四、新时空变换带来的新时空观1、有关相对论时间的“傻问题”2、关于相对论的“怪问题”3、关于“双…...
仓库使用综合练习
目录 1、使用mysql:5.6和 owncloud 镜像,构建一个个人网盘。 2、安装搭建私有仓库 Harbor 3、编写Dockerfile制作Web应用系统nginx镜像,生成镜像nginx:v1.1,并推送其到私有仓库。 4、Dockerfile快速搭建自己专属的LAMP环境,生…...
如何在前端实现WebSocket发送和接收TCP消息(多线程模式)
目录 第一步:创建WebSocket连接第二步:监听WebSocket事件第三步:发送消息第四步:后端处理函数说明 当在前端实现WebSocket发送和接收TCP消息时,可以使用以下步骤来实现多线程模式。本文将详细介绍如何在前端实现WebSoc…...
VB.NET通过VB6 ActiveX DLL调用PowerBasic及FreeBasic动态库
前面说的Delphi通过Activex DLL同时调用PowerBasic和FreeBasic写的DLL,是在WINDOWS基础平台上完成的。 而 .NET平台是架在WINDOWS基础平台之上的,它的上面VB.NET或C#等开发的APP程序,下面写一下用VB.NET,通过VB6注册的Activex DLL…...
怎样不引入图片实现前端css实现x关闭按钮
首先初始化一个dom节点 <span class"closeButton"></span>设置样式 .closeButton {width: 12px;height: 12px;margin-top: 5px;margin-right: 5px;float: right;cursor: pointer;color: #105c86;}通过伪元素before after画两条线 margin-left 的设置是…...
SpringBoot实现文件下载的多种方式
SpringBoot实现文件下载的几种方式 1. 将文件以流的形式一次性读取到内存,通过响应输出流输出到前端1.1 下载文件 2. 将输入流中的数据循环写入到响应输出流中,而不是一次性读取到内存,通过响应输出流输出到前端3. 下载网络文件到本地4. 网络…...
uniapp简单版语音播放
mounted() {this.ScanAudio(http://118.178.137.235:88/ipoker.mp3, 3); // 开始播放音频},ScanAudio(url, count) {// 递归终止条件:当循环次数小于等于 0 时,停止递归if (count < 0) return;// 创建内部音频上下文对象var music uni.createInnerAu…...
前端三剑客入门一文解决
文章目录 HTML快速开发网站Flask页面结构标签基础标签超链接图片列表下拉框表格input系列多行文本form表单 网络请求HTML案例 CSSCSS盒模型CSS样式定义CSS选择器 CSS样式使用1. 在标签上直接写2. 在head标签中写3.写到css文件中 标签样式1. 高度和宽度2. 块级和行内标签3.字体设…...
php curl apache 超时 500错误
web请求超过40s 就返回500错误 php的超时时间 set_time_limit无效 curl CURLOPT_TIMEOUT 设置请求时间 无效 设置apache Timeout 链接超时 无效 最后添加 Fcgid才可以 apache 配置文件 httpd.conf <IfModule mod_fcgid.c>FcgidProcessLifeTime 10000FcgidIOTimeout 1000…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...
边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...
