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

news2025/1/12 16:08:25

在这里插入图片描述

一、原因

在 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 := i
    go 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 := i
    arr = 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 := i
    go 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.coloradmin.cn/o/558210.html

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

相关文章

每日一练 | 网络工程师软考真题 Day8

1、某客户端采用ping命令检测网络连接故障时&#xff0c;发现可以ping通127.0.0.1及本机的IP地址&#xff0c;但无法ping通同一网段内其他工作正常的计算机的IP地址。该客户端的故障可能是 。 A&#xff0e;TCP/IP协议不能正常工作 B&#xff0e;本机网卡不能正常工作 …

80%的人加班都是因为没搞清业务需求:小白如何做好需求调研?

做过项目的都知道&#xff0c;收集和明确需求并非易事&#xff0c;尤其是挖掘需求方详细、深层次的需求。 很多企业在做需求调研时&#xff0c;经常由于双方对问题描述和理解上的差异&#xff0c;使得需求在不断传递的过程中发生较大的偏差&#xff0c;结果导致最终开发出来的…

Head-Free Lightweight Semantic Segmentation with Linear Transformer 新颖的分割网络

现有的语义分割网络基本都是编码解码结构&#xff0c;新的语义分割网络主要都是在解码阶段添加新的不同模块&#xff0c;提高解码阶段特征处理能力&#xff0c;从而实现语义分割。而这篇文章主要是去除了解码阶段&#xff0c;把工作重心放在了编码阶段。它采用并行架构来利用原…

chatgpt赋能Python-python_isdigit_小数

Python isdigit 小数&#xff1a;如何检测字符串是否为数字&#xff1f; 在Python中&#xff0c;字符串是一种非常常见的数据类型。有时我们需要将字符串转换成数字类型&#xff0c;以便于进行各种计算&#xff0c;比如统计数据、计算平均数等等。在这种情况下&#xff0c;我们…

四、Spring从入门到改行

一、Spring概述 Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器&#xff08;框架&#xff09;。 二、Spring基础程序 1、pom.xml中导入依赖 <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifact…

chatgpt赋能Python-python_ip地址处理

Python IP地址处理 在网络通信中&#xff0c;IP地址是非常重要的内容。Python作为一门强大的编程语言&#xff0c;自然也能处理IP地址。本文将介绍Python处理IP地址的方法&#xff0c;并提供一些实用的例子。 IP地址的表示方式 IP地址是一个32位的二进制数&#xff0c;通常表…

chatgpt赋能Python-python_if_跳过

Python中if语句的跳过和应用 Python的if语句是编程中常用的一条条件语句&#xff0c;它允许开发者根据不同的情况&#xff0c;对代码进行不同的处理。if语句也带来了一些跳过语句&#xff0c;可以有效地帮助开发者避免不必要的操作&#xff0c;提高程序运行效率。本文将介绍Py…

toString 自定义逻辑 过滤 limit ignore 字段 ReflectionToStringBuilder ToStringBuilder

ToStringBuilder 有自己的属性,style, 也有工具方法,直接代理了ReflectionToStringBuilder // ReflectionToStringBuilder 非并发安全,需每次都new ReflectionToStringBuilder reflectionToStringBuilder new ReflectionToStringBuilder(this, org.apache.commons.lang3.build…

2023新版Spring6全新讲解-HelloSpring入门案例

Spring的入门案例 Spring6.0要求的JDK最低版本是17 我们在本课程中使用的版本是5.x版本。这个Spring5的JDK的最低要求是8 一、环境要求 JDK&#xff1a;8 Maven&#xff1a;3.6 Spring:5.3.27 开发工具&#xff1a;IDEA 2021.1.1 二、项目创建 1. 构建项目 在idea中&…

互联网医院系统的优势与挑战:现状调研分析

随着互联网技术的不断发展和普及&#xff0c;互联网医院系统也逐渐走进人们的视野。这种以互联网技术为支撑的医疗服务模式&#xff0c;可以为患者提供更加便捷、快速和高效的医疗服务&#xff0c;同时也可以缓解医院资源短缺的问题。 一、互联网医院系统的优势 方便快捷 互联…

chatgpt赋能Python-python_josn

Python Json&#xff1a;简介与应用 什么是Json&#xff1f; JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;具有良好的可读性和易于解析性&#xff0c;广泛用于Web数据传输和API交互中。 Python中的Json模块 在Python中&…

chatgpt赋能Python-python_imessage

Python iMessage – 给你的消息通讯锦上添花 作为一款风靡全球的通讯工具&#xff0c;iMessage的使用率在近年来不断攀升。iMessage的简洁易用性以及其在安全性和隐私方面的优势&#xff0c;经常使得其成为个人和商业用户的首选。而Python iMessage&#xff0c;则为这项通讯工…

Day49【动态规划】121.买卖股票的最佳时机、122.买卖股票的最佳时机II

121.买卖股票的最佳时机 力扣题目链接/文章讲解 视频讲解 动态规划五部曲&#xff01; 1、确定 dp 数组下标及值的含义 先想想本题 dp 应该怎么定义&#xff0c;别忘了之前说的&#xff0c;dp 数组的下标能够表示状态 在股票问题中&#xff0c;某个状态需要描述在某天&…

煤矿电子封条智能监管系统 TensorFlow

煤矿电子封条智能监管系统基于TensorFlowAI开源的机器学习的框架&#xff0c;煤矿电子封条智能监管系统可以对设备及人员行为和穿戴着装进行实时监测和管理。相比于其他的机器学习框架&#xff0c;Tensorflow 框架是最适用于工业部署的一个机器学习框架&#xff0c;换句话说&am…

数链科技用飞桨和文心大模型打造大宗商品数字供应链系统,提升行业透明度及标准化

大宗商品行业市场规模巨大、关系国计民生&#xff0c;它的三个核心类别——能源商品、基础原材料、农副产品均在我国经济发展进程中起着举足轻重的作用。这其中&#xff0c;大宗商品供应链的顺畅运行和稳定发展对整个产业链的运作至关重要。 然而传统大宗商品供应链普遍存在交易…

测试的正向思维和反向思维

测试的正向思维和反向思维 正向思维和反向思维是两种不同的思考方式&#xff0c;它们在决策和问题解决中起着重要的作用。 正向思维指的是以积极、乐观的态度看待事情&#xff0c;从优点出发&#xff0c;寻找解决问题的方法和途径。正向思维的人通常更容易接受挑战&#xff0c;…

Guitar Pro8最新五线谱转六线谱软件

提到吉他谱的编写&#xff0c;有一款软件总是被第一时间想到&#xff0c;那就是Guitar Pro。 Guitar Pro8所开启的音乐未来&#xff0c;不仅仅是一种全新的学习乐器方式。更在于对整个乐队的掌控&#xff0c;将弦乐的悠然和打击乐的劲爆尽收其间&#xff01; 同时&#xff0c;…

vmware安装debian 11.7.0

vmware安装debian 11.7.0 1、下载镜像2、创建并安装debian 11虚拟机2.1 选择 Graphical install2.2、选择安装过程显示语言和系统语言2.3、选择地区2.4、键盘映射2.5、设置主机名-debian2.6、设置网络-直接跳过2.7、设置root密码2.8、创建普通账户2.9、为普通账户设置密码2.10、…

ClickHouse:(一)安装部署

1.准备工作 1.2关闭防火墙 防火墙的开启、关闭、禁用命令 &#xff08;1&#xff09;设置开机启用防火墙&#xff1a;systemctl enable firewalld.service&#xff08;2&#xff09;设置开机禁用防火墙&#xff1a;systemctl disable firewalld.service&#xff08;3&#x…

VIBRO-METER VM600 AMC8 8个温度或过程监控通道

VM600 AMC8模拟监控卡 8个温度或过程监控通道每个通道1个已处理输出&#xff0c;每个多通道1个已处理输出(每个am c8 4个)高度可配置的卡支持使用热电偶和/或RTD进行温度监控&#xff0c;以及使用电流和/或电压输入进行过程监控高度集成的卡对(带IOC8T)包括DC输出、继电器和串行…