Golang-循环变量作用域针对那些数据类型会出现问题

news/2024/10/30 21:21:59/

在这里插入图片描述

一、原因

在 Go 中,循环变量的作用域是整个 for 循环语句块。因此,循环变量在 for 循环语句块中的代码都是可见的。

但是,当循环变量的值被用于闭包, 协程或者使用指针类型的数据结构时,会出现一些问题。这是因为循环变量的值在每一次迭代中都会被重新赋值,所以闭包或指针可能会看到循环变量的最后一个值。

二、情况分析

一般说来,循环变量作用域的问题主要出现在以下几种情况:

1. 循环变量被使用在闭包中

循环变量被闭包中使用是一个常见的问题,下面是一些示例代码:

  1. 访问循环变量 i 的闭包:
var arr []*int
for i := 0; i < 3; i++ {arr = append(arr, &i)
}
for _, f := range arr {fmt.Print(*f)
}

输出结果为 “333”,因为闭包访问的是循环变量的地址,而不是值。

  1. 在 for 循环中自增一个变量 j,然后将其作为参数传递给一个闭包:
for i := 0; i < 3; i++ {j := igo func() {fmt.Print(j)}()
}

输出结果是 “012”,这是因为闭包捕获的是 j 的值,每个goroutine都会访问自己的 j 副本。

  1. 在使用defer关键字的时候,会出现和闭包一样的问题。
for i := 0; i < 3; i++ {defer fmt.Print(i)
}

这个代码的输出结果是 “321”,因为 defer 语句在函数返回前执行,所以闭包捕获的都是同一个循环变量的地址。

  1. 在使用函数字面量的时候,同样会出现和闭包一样的问题。
func main() {fns := make([]func(), 0)for i := 0; i < 3; i++ {fns = append(fns, func() {fmt.Print(i)})}for _, f := range fns {f()}
}

输出结果为 “333”,这是因为函数字面量捕获的是变量 i 的地址,而 i 的值在循环结束后一直是 3。

2. 循环变量被使用在指针类型数据结构中

循环变量被使用在指针类型数据结构中也是一个常见的问题,下面是一些示例代码:

  1. 访问循环变量 i 的指针类型数据结构:
var arr []*int
for i := 0; i < 3; i++ {arr = append(arr, &i)
}
for _, p := range arr {fmt.Print(*p)
}

输出结果为 “333”,因为指针类型数据结构中保存的是循环变量的地址,而不是值。

  1. 在循环中申请一个变量 j,然后将其作为指针类型数据结构的元素:
arr := make([]*int, 0)
for i := 0; i < 3; i++ {j := iarr = append(arr, &j)
}
for _, p := range arr {fmt.Print(*p)
}

输出结果是 “012”,这是因为指针类型数据结构保存的是 j 的地址,每个元素访问的是自己所指向的值。

3.循环变量被使用在协程中

循环变量被使用在协程中是一个常见的问题,下面是一些示例代码:

  1. 访问循环变量 i 的协程:
for i := 0; i < 3; i++ {go func() {fmt.Print(i)}()
}

输出结果为 “333”,因为协程访问的是循环变量的地址,而不是值。

  1. 在循环中申请一个变量 j,然后将其作为参数传递给一个协程:
for i := 0; i < 3; i++ {j := igo func() {fmt.Print(j)}()
}

输出结果是 “012”,这是因为协程捕获的是 j 的值,每个协程都会访问自己的 j 副本。

  1. 在使用defer关键字的时候,同样会出现和协程一样的问题。
for i := 0; i < 3; i++ {defer fmt.Print(i)
}

这个代码的输出结果是 “321”,因为 defer 语句在函数返回前执行,所以协程捕获的都是同一个循环变量的地址。

三、解决方式

为了避免这些问题,可以在 for 循环语句块内部声明一个新的变量,以便每一次迭代都有自己的独立的值。比如,使用一个局部变量存储循环变量的值,然后在闭包或指针数据结构中使用该局部变量的值。例如:

arr := make([]*int, 0)
for i := 0; i < 3; i++ {j := i  // 创建新的变量arr = append(arr, &j)
}
for _, p := range arr {fmt.Print(**p)
}

这样就可以保证每个元素都指向不同的变量,输出的结果也会更加准确。


http://www.ppmy.cn/news/88920.html

相关文章

windows系统python3.7版本pyspider安装

环境&#xff1a;很多的python版本都尝试过安装pyspider&#xff0c;网上多数让python3.6安装&#xff0c;说是这个环境是最佳的环境&#xff0c;测试安装最方便快捷&#xff0c;但是一直报result_worker starting…&#xff01;&#xff01;&#xff01;&#xff0c;卡死在界面…

Python itertools模块

count 功能详解 count(start0,step1) 函数有两个参数&#xff0c;其中 step 是默认参数&#xff0c;可选的&#xff0c;默认值为 1。该函数返回一个新的迭代器&#xff0c;从 start 开始&#xff0c;返回以 step 为步长的均匀间隔的值。 import itertoolsx itertools.count(…

JSP+sql实验教学管理系统(系统+论文+开题报告+封面+中期检查表+英文文献)

现在的实验教学网络管理系统存在实验题目分发慢,文档交换不方便,师生交流困难等方面的问题。为了解决现有系统的这些问题,特开发新的实验教学网络管理系统。 作者以实际应用为开发背景,运用软件工程原理和开发方法,采用当前网络开发主流技术,结合JSP和SQL数据库技术,设…

设计事务所项目管理指南

在数字化的浪潮下&#xff0c;各行各业都面临着升级转型的问题。对设计团队而言&#xff0c;传统的管理方式已经无法满足日益前进的团队需求。 设计事务所可能存在的管理问题&#xff1a; 1&#xff0c;项目过程中信息流通慢&#xff0c;成员工作进度无法及时同步&#xff1b; …

springboot+vue学生综合测评系统(java项目源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的学生综合测评系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风…

四川师范大学何云:事项法会计从五大方面助力企业创造价值

近日&#xff0c;由用友主办的「智能会计 价值财务」2023企业数智化财务创新峰会收官站圆满举办。来自知名院校的专家学者、央国企等大型企业财务领路人相约成都&#xff0c;一同见证“智能会计”新时代的到来&#xff0c;并肩探讨“价值财务”新主张。 为更好传递智能会计对企…

iOS-最全的App上架教程

App上架教程 在上架App之前想要进行真机测试的同学&#xff0c;请查看《iOS- 最全的真机测试教程》&#xff0c;里面包含如何让多台电脑同时上架App和真机调试。 P12文件的使用详解 注意&#xff1a; 同样可以在Build Setting 的sign中设置证书&#xff0c;但是有点麻烦&…

如何使用 Fail2ban 防止对 Linux 的暴力攻击?

在当今数字化世界中&#xff0c;网络安全成为了一个极其重要的话题。Linux 作为一种广泛使用的操作系统&#xff0c;也面临着各种网络攻击的风险&#xff0c;包括暴力攻击、密码破解和恶意登录等。为了保护 Linux 系统的安全&#xff0c;我们可以使用 Fail2ban 这样的工具来防止…