golang range循环内部
一个疑惑和三个例子
下面的程序会无限执行下去吗?
func main() {v := []int{1, 2, 3}for i := range v {v = append(v, i)} }
答案
思考一下下面三个例子的结果。
func IndexArray() {a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}for i := range a {a[3] = 100if i == 3 {fmt.Println("IndexArray", i, a[i])}} }func IndexValueArray() {a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}for i, v := range a {a[3] = 100if i == 3 {fmt.Println("IndexValueArray", i, v)}} }func IndexValueArrayPtr() {a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}for i, v := range &a {a[3] = 100if i == 3 {fmt.Println("IndexValueArrayPtr", i, v)}} }
答案
range左值
可以 是 i := range 或者 i,v := range ,变量已经被预先定义的话,这个 := 当然可以是 = 。
要注意的是 用 := 时,前面变量是被重用的,想当于第一次用的是 := 后续循环用的是 = 。
range右值
可以是以下类型,或者返回以下类型的表达式
- array 或 array的指针
- slice
- string
- map
- 可从中接收的channel
表达式会在loop开始前计算。
如果只是i := range arr 或者 i := range *arr 这种只要数组索引的循环,由于数组是不可变的,因此在编译时候,可能直接计算len(arr),编译器直接用这个常量结果优化掉range。
分析数据类型
再go中,每次分配都伴随copy,比如赋值,函数参数等。
以下几个类型的底层数据结构:
所以将一个数组分配给一个array,内存级别是整个array的一次复制。
string和slice的分配只是这两个类型头,或者叫做类型元信息结构体的复制,底层数组是没变化的。
map和channel也一样,只是指针的复制。
编译器实现
range本质是for语句的一个语法糖。
编译器会在循环开始前copy一次循环对象。编译器的编译后的逻辑:
array:
slice:
可以看出数组是值类型会被整个复制一遍,大数组直接循环代价不小。应该使用数组指针来做循环对象,复制一个指针还是代价小的。
关于map一个重要的信息
如果循环过程中,map的一个key-value没有被遍历到就被删除了,这个值在后续的遍历中不会出现。
遍历过程中一个key-value被创建了,继续遍历可能会遍历到这个key-value,也可能被跳过。这个应该涉及map底层的分桶实现。以后有机会介绍一下。
总之,把range理解成一个函数,被遍历的对象当作range的参数,这样理解或许更好。
以上实际是 理解半翻译 一篇博客:Go Range Loop Internals
转载于:https://www.cnblogs.com/adarking/p/8629191.html
golang range循环内部相关推荐
- golang for循环_10. Go语言流程控制:for 循环
本文原文:http://golang.iswbm.com Github:http://github.com/iswbm/GolangCodingTime Go里的流程控制方法还是挺丰富,整理了下有如下 ...
- Golang for循环
Golang for循环 for循环是Golang唯一的循环语句.for循环主要是用在挨个挨个取出数据的情况下.比如老师点名,老师点名的时候不可能一口气说出全班同学的名字,所以只能一个一个的点名,那么 ...
- stm32怎么调用for循环内部的变量_循环中的异步amp;amp;循环中的闭包
在这之前先要了解一下 for循环中let 和var的区别 var 是函数级作用域或者全局作用域,let是块级作用域 看一个例子 function foo() { for (var ...
- 循环内部异步函数处理相关问题解析
需求分析:根据一级标题ID筛选出所有对应的二级标题,返回一级标题ID,标题名和二级标题ID,标题名组成的数组 问题:通过forEach遍历所有一级标题取对应的ID,根据ID条件查找所有的二级标题,遍历 ...
- Go语言自学系列 | golang for range循环
视频来源:B站<golang入门到项目实战 [2021最新Go语言教程,没有废话,纯干货!持续更新中...]> 一边学习一边整理老师的课程内容及试验笔记,并与大家分享,侵权即删,谢谢支持! ...
- golang range 遍历读写数据问题
在Golang中使用 for range 语句进行迭代非常的便捷,但在涉及到指针时就得小心一点了. 下面的代码中定义了一个元素类型为 *int 的通道 ch : package mainimport ...
- Golang range解析
目录 文章目录 目录 正文 正文 golang中的range是一个很常用的功能,可以遍历一个数组,切片等等,但是使用过程需要注意一个细节. 先举个栗子: package mainimport (&qu ...
- golang for循环的重新认识
顺手写了,编译器报错 package mainimport ("fmt""time" )var ch1 = make(chan int) var ch2 = m ...
- golang for 循环中使用协程的问题
两个例子 package mainimport ("fmt""time" )func Process1(tasks []string) {for _, task ...
- 开发这么久你真知道for循环内部执行顺序吗?
for(System.out.print('a');num <= 3;System.out.print('c'),num++){System.out.print('b');} abcbcbc f ...
最新文章
- Python 常用排序Demo|冒、插、快、希等入门算法
- PHP学习总结(会话控制)
- Redis遍历方式思考--字典扩容方式
- python爬虫:两种方法模拟登录博客园
- 潍职e校帮APP功能简介
- python中定义变量为啥要用下划线_关于python中带下划线的变量和函数 的意义
- 数据集怎么导出_PCA算法 | 数据集特征数量太多怎么办?用这个算法对它降维打击...
- SPA是什么及原生js实现简易SPA单页面
- 怎么获取微信公众号的音频视频
- 请收下这 72 个炫酷的 CSS 技巧
- 绿联硬盘盒linux驱动,绿联 USB3.0 SATA 接口通用移动硬盘盒子体验与选购技巧
- (个人记录向)75寸电视选购
- intellijIdea新手上路
- Thinkphp5-开启调试模式
- vue-seamless-scroll 从入坑到放弃
- Ubuntu PX4无人机仿真环境配置
- Ubuntu16.04+cuda8.0+GTX TITAN X安装配置
- 首发仿拼多多源码,程序完整版+安装教程+完美运营
- 最简单DIY蓝牙PS2遥控器控制蓝牙智能小车
- PHP Apache Mysql的配置搭建及多站点配置