Golang中for和for range语句的使用技巧、对比及常见的避坑

前言

基础语法不再赘述,写这个原因是之前的某次面试被问道了,我知道会导致问题但具体答下来不是很通顺。再回想自己开发过程中,很多地方都是使用到了for/for range,但是却从没注意过一些细节,因此专门学习一下进行记录。

对一个数组循环,for range,使用kv时候有什么要注意的吗?
这个是当时面经记录的问题。因此顺着这里开始进行学习。

在这里插入图片描述

for和for range基本语法

for的用法大概可以类比C++里面的for和while

//类似C++的for 
for i := 0; i < 10; i++ {fmt.Println(i)
}
//类似C++的while
j := 0
for j < 10 {fmt.Println(j)j++
}//死循环
for {fmt.Println("无限循环")
}

fo range用法大概可以类比python的range。但是golang中他的用法更多,大致四种

//遍历数组:
numbers := [3]int{1, 2, 3}
for index, value := range numbers {fmt.Printf("索引:%d 值:%d\n", index, value)
}
//遍历切片:
names := []string{"Alice", "Bob", "Charlie"}
for index, name := range names {fmt.Printf("索引:%d 值:%s\n", index, name)
}
//遍历 map:
ages := map[string]int{"Alice": 25, "Bob": 30, "Charlie": 35}
for name, age := range ages {fmt.Printf("%s 的年龄是 %d 岁\n", name, age)
}
//遍历字符串:
sentence := "Hello, 世界"
for index, char := range sentence {fmt.Printf("索引:%d 字符:%c\n", index, char)
}

for和for range的区别

对于一个数组,例如a[3]={3.2.1},可以通过两种方式进行遍历:


func main() {fmt.Println("下面是for range遍历")var m = []int{1, 2, 3}for k, v := range m {fmt.Println(k, v)fmt.Println(&k, &v)}fmt.Println("下面是for遍历")for i := 0; i < 3; i++ {fmt.Println(i, m[i])fmt.Println(&i, &m[i])}
}

其结果如下:

在这里插入图片描述

我们可以发现,输出的结果是一样的,但地址却不一样:
因此这便是二者的本质区别——
1、range遍历在开始遍历数据之前,会先拷贝一份被遍历的数据。所以在遍历过程中去修改被遍历的数据,只是修改拷贝的数据,不会影响到原数据。
2、range在遍历值类型时,其中的v是一个局部变量,只会声明初始化一次,之后每次循环时重新赋值覆盖前面的。

常见的坑

通过指针取值

//此代码来自`https://zhuanlan.zhihu.com/p/105435646`
arr := [2]int{1, 2}
res := []*int{}
for _, v := range arr {res = append(res, &v)
}
//expect: 1 2
fmt.Println(*res[0],*res[1]) 
//but output: 2 2

这个是由于上述的区别2——v是一个只声明一次的局部变量。
修改方案两种:1、通过arr[k]获取值,而不是v。
2、使用一个局部变量:tmp :=v,之后对tmp处理。

循环中添加元素是否会导致死循环

func main() {s := []int{0, 1}for _, v := range s {s = append(s, v)}fmt.Printf("s=%v\n", s)
}

大致意思是这样会不会死循环?
这个是上面的性质1。range因为是对复制的数据在操作,所以不会影响。普通的for则会影响。

https://cloud.tencent.com/developer/article/1925475
此部分具体参考此例即可。

对大数据的操作

对于很大数据的数组,若采取range遍历,因为复制的缘故,所以会导致开销巨大。(具体见下的性能分析)
但是在大数据的数组下,使用range去重置(全部赋值为0),效率是高的。原因是内存是连续的,编译器会直接清空这一片的内存。具体讲解见此

demo和源码看这里的3和4

对于map的操作

具体来说,就是边遍历边新增/删除。删除了的不可能再遍历到,新增的可能再遍历到(不一定)。

原因:map内部实现是一个链式hash表,为了保证无顺序,初始化时会随机一个遍历开始的位置,所以新增的元素被遍历到就变的不确定了,同样删除也是一个道理,但是删除元素后边就不会出现,所以一定不会被遍历到。

具体参考此文的最后部分

range中开goroutine

func main() {var m = []int{1, 2, 3}for i := range m {go func() {fmt.Print(i)}()}time.Sleep(time.Millisecond)}

会发现输出结果有随机性:发现结果是222。原因是上述的那个,k、v是同一值,他并没有保存到goroutine的栈中。
解决方法还是局部变量,但可能出现012、210、102这样的值…原因是运行太快了,所以顺序不一定…

附1:range遍历的性能分析

for range需要进行一步复制操作,因此显然需要比for更多的性能开销。但是对于切片来说,因为切片的副本和原切片都是指向数组的地址,所以性能一样。
具体见此文。

https://blog.csdn.net/EDDYCJY/article/details/124701572

附2:一个坑中坑——map的range遍历并不是随机

具体参考此文

结论是:第一位的元素会有更高的概率被首先选中。因此不可用map遍历的随机性,作为随机选择map中元素的方法。

参考资源

Go 处理大数组:使用 for range 还是 for 循环?
Go的循环遍历使用小坑
Go 中for range的一个坑
Go语言中for-range使用踩坑指南
Dig101 - Go之for-range排坑指南
Golang 语言 for 和 for-range 的区别
5.1 for 和 range #

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

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

相关文章

【C++20】编译期检测所有未定义行为undefined behavior和内存泄漏(不借助编译选项以及任何外部工具)

文章目录 一、未定义行为Undefined Behavior(UB)1.返回一个未初始化的局部变量的值2.数组越界访问3.有符号数的常量表达式溢出4.new与delete5.vector6.空指针解引用 参考 一、未定义行为Undefined Behavior(UB) 在C中&#xff0c;未定义行为&#xff08;Undefined Behavior&am…

Angular中的NgZone.run()有什么用?

在Angular中&#xff0c;NgZone是一个服务&#xff0c;用于管理异步任务的执行&#xff0c;并提供一种在Angular区域内或外部显式运行代码的方式。区域&#xff08;Zone&#xff09;的概念用于跟踪和拦截异步操作&#xff0c;例如Promises、事件和定时器&#xff0c;以便在需要…

K8S中SC、PV、PVC的理解

存储类&#xff08;StorageClass&#xff09;定义了持久卷声明&#xff08;PersistentVolumeClaim&#xff09;所需的属性和行为&#xff0c;而持久卷&#xff08;PersistentVolume&#xff09;是实际的存储资源&#xff0c;持久卷声明&#xff08;PersistentVolumeClaim&#…

平衡搜索二叉树(AVL树)

前言 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查 找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年 发明了一种解决上述…

代码随想录算法训练营第三十天(回溯算法篇)|491. 非递减子序列, 46. 全排列,47. 全排列Ⅱ

491. 非递减子序列 题目链接&#xff1a;491. 非递减子序列 - 力扣&#xff08;LeetCode&#xff09; 思路 1. 判断是否将当前遍历到的元素添加到path中。 如果当前元素大于等于前一个元素&#xff0c;满足条件&#xff0c;但前提是当前的i>0&#xff0c;可若加上i>0…

vue中鼠标拖动触发滚动条的移动

前言 在做后端管理系统中&#xff0c;像弹窗或大的表单时&#xff0c;经常会有滚动条的出现&#xff0c;但有些时候如流程、图片等操作时&#xff0c;仅仅使用鼠标拖动滚动条操作不太方便&#xff0c;如果使用鼠标拖拽图片或容器来触发滚动条的移动就比较方便了 功能设计 如…

5分钟带你了解RESTful

RESTful API是一种基于HTTP协议的API设计风格&#xff0c;它以资源为核心&#xff0c;通过URL来访问和操作资源的状态。RESTful API遵循一些约定俗称的规则&#xff0c;包括使用HTTP动词&#xff08;GET、POST、PUT、DELETE等&#xff09;来操作资源&#xff0c;使用HTTP状态码…

开源软件运维安全防护的六个手段

开源&#xff0c;顾名思义&#xff0c;即开放软件源代码。代码贡献者可将自己编写的程序提交到开源社区的公开平台上&#xff0c;其他代码开发者如有类似的功能需求可以不必再自己动脑动手编写代码&#xff0c;而是直接集成、修改或应用贡献者公开的代码。 开源软件是通过特定…

深圳公司减资 深圳公司变更 深圳公司减资流程

新公司法从2024年7月1日起&#xff0c;全体股东需要在公司成立之日起五年内缴足认缴的出资额。这一变革在社会上引发了广泛的关注和热议。 如果您公司注册资金巨大&#xff0c;数千万甚至上亿&#xff0c;那么到了出资期限后&#xff0c;股东出资可能会面临困难。此时&#xf…

LeetCode(454)四数相加 II⭐⭐

给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) &#xff0c;使得 A[i] B[j] C[k] D[l] 0。 为了使问题简单化&#xff0c;所有的 A, B, C, D 具有相同的长度 N&#xff0c;且 0 ≤ N ≤ 500 。所有整数的范围在 -2^28 到 2^28 - 1 之间&#…

Pinia处学习

修改数据的三种方式: mutate本次变化的数据,state时store中的数据

LeetCode每周五题_2024/01/08~01/12

文章目录 447. 回旋镖的数量 [01/08]题目题解 2707. 字符串中的额外字符 [01/09]题目题解 447. 回旋镖的数量 [01/08] 447. 回旋镖的数量 题目 给定平面上 n 对 互不相同 的点 points &#xff0c;其中 points[i] [xi, yi] 。回旋镖 是由点 (i, j, k) 表示的元组 &#xff0…

大模型训练营Day2 homework

1.使用 InternLM-Chat-7B 模型生成 300 字的小故事 2.熟悉 hugging face 下载功能&#xff0c;使用 huggingface_hub python 包&#xff0c;下载 InternLM-20B 的 config.json 文件到本地&#xff1a; 下面开始下载和推广大模型的相关的包&#xff1a; 这里需要在本地上&…

uniapp自定义底部导航栏

1.新建 nav-custom.vue组件 <template><view class"nav-box" :style"{height:heightpx,background:bgColor}"><!-- 自定义导航栏 --><view class"status_bar" :style"{height:statusBarHeightpx}"><!-- u…

@Transactional 事务注解

第一、先简单介绍一下Spring事务的传播行为 所谓事务的传播行为是指&#xff0c;如果在开始当前事务之前&#xff0c;一个事务上下文已经存在&#xff0c;此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量&…

HarmonyOS应用开发学习笔记 UIAbility组件间交互 UIAbility启动,页面跳转结果回调

1、 HarmoryOS Ability页面的生命周期 2、 Component自定义组件 3、HarmonyOS 应用开发学习笔记 ets组件生命周期 4、HarmonyOS 应用开发学习笔记 ets组件样式定义 Styles装饰器&#xff1a;定义组件重用样式 Extend装饰器&#xff1a;定义扩展组件样式 5、HarmonyOS 应用开发…

MySQL的体系结构(超全总结版)

MySQL组成 连接池组件管理服务和工具组件SQL接口组件查询分析器组件优化器组件缓冲组件插件式存储引擎物理文件 存储引擎 InnoDB存储引擎 主要面向OLTP(在线事务处理)方面的应用&#xff0c;特点是行锁设计、支持外键&#xff0c;默认情况下读取操作不会产生锁。通过使用多…

布隆过滤器的原理

布隆过滤器&#xff08;Bloom Filter&#xff09;是由Burton Howard Bloom在1970年提出的一种空间效率很高的概率型数据结构&#xff0c;它用来测试一个元素是否在一个集合中。布隆过滤器可以非常快速地进行插入和查询操作&#xff0c;并且非常节省空间&#xff0c;但它有一个小…

Centos7下升级gcc/g++版本(简单 + 避坑)

在 Centos7 下&#xff0c;使用 yum 安装高版本的 gcc/g 最简单&#xff1a; yum -y install centos-release-scl yum -y install devtoolset-11-gcc devtoolset-11-gcc-c devtoolset-11-binutils需要安装哪个个版本的gcc/g&#xff0c;就把数字替换成对应的版本号。例如上面代…

船舶3d虚拟展厅线上制作降低展示成本

VR线上虚拟展厅漫游搭建平台是一种新兴的技术&#xff0c;它能够为用户提供更加真实、沉浸式的体验。目前&#xff0c;市场上有许多公司提供VR线上虚拟展厅漫游搭建平台技术服务&#xff0c;为客户提供全方位的支持。 首先&#xff0c;这些公司通常会提供专业的策划和设计服务。…