【go】忽略range循环中使用指针的影响?

embedded/2025/3/26 4:25:58/

经典面试题:

func main() {s := Store{m: make(map[string]*Customer),}s.storeCustomers4([]Customer{{ID: "1", Balance: 10},{ID: "2", Balance: -10},{ID: "3", Balance: 0},})print(s.m)
}func (s *Store) storeCustomers(customers []Customer) {for _, customer := range customers {fmt.Printf("%p\n", &customer)s.m[customer.ID] = &customer}
}

说最后输出的都是id:3 。。。
but,这一切都在1.23 改变了,这个有点反人类的指针指向最后一个,被1.23 解决了

Go 1.23中关于Range循环的变化

Go 1.23版本对range循环引入了一个重要的行为变更,这是Go 1.x语义演进的一个罕见例子。以下是这个变化的详细说明:

主要变化:迭代变量的地址不再复用

在Go 1.23之前,range循环的迭代变量在每次迭代中都使用相同的内存地址,只是值会改变。这导致了我们讨论的问题——当在循环中获取迭代变量的地址时,所有迭代都返回相同的地址。

Go 1.23的变化

  • 每次迭代现在会为迭代变量分配新的内存地址
  • 这意味着获取迭代变量的地址(如&customer)在每次迭代中会返回不同的地址

变更的动机

这个变更的主要动机是解决一个常见的错误来源和困惑点:

  1. 这个问题已经成为Go开发者的常见痛点,尤其是在使用指针、闭包和goroutine时
  2. 许多开发者对此行为感到意外,因为它与直觉相悖
  3. 它导致了难以调试的错误,特别是在并发程序中

变更的官方说明

这个变更是在提案#56739中提出并实现的,标题为"cmd/compile: for-range loop iteration variables should not be reused"。

提案的核心论点是:

  • range变量复用导致了许多意外错误
  • 新的行为更符合开发者的直觉和期望
  • 这种修改很少会破坏依赖旧行为的正确代码

技术实现

在内部实现上,Go编译器现在会:

  1. 在循环的每次迭代中重新分配迭代变量
  2. 这适用于所有形式的range循环(切片、数组、映射、通道等)
  3. 对于for i, v := range x形式,iv都会在每次迭代中获得新的地址

对现有代码的影响

这个变更的影响主要是积极的:

  1. 修复了常见错误

    for _, v := range items {pointers = append(pointers, &v) // 现在正常工作!
    }
    
  2. 对goroutine更安全

    for _, v := range items {go func() {fmt.Println(v) // 现在捕获的是当前迭代的值}()
    }
    
  3. 闭包捕获更符合直觉

    funcs := make([]func(), 0, len(items))
    for _, v := range items {funcs = append(funcs, func() {fmt.Println(v) // 现在每个函数打印不同的值})
    }
    

向后兼容性考虑

这是一个罕见的例外,Go团队决定在Go 1.x版本中改变语言行为。通常,Go的兼容性承诺禁止这类变更。

如果您的代码需要与较旧的Go版本兼容,您仍然应该:

  1. 在循环中创建局部变量
  2. 使用函数参数捕获当前值
  3. 使用索引形式的range循环

总结

Go 1.23中的这个变化是对语言的重要改进:

  1. 它解决了一个常见的错误来源
  2. 使代码行为更符合开发者的直觉
  3. 简化了与指针、闭包和goroutine相关的代码

这个变更展示了Go团队在语言演进中的谨慎平衡——在大多数情况下保持严格兼容性,但在必要时也愿意进行精心考虑的改进,即使这意味着改变现有行为。


http://www.ppmy.cn/embedded/174505.html

相关文章

Unity-VR中使用手柄点击UI

拓展BaseInputModule 使用鼠标模拟VR设备操作 using UnityEngine.EventSystems; using UnityEngine; namespace Framework.VR {/// <summary>///按下鼠标左键&#xff0c;手柄Z轴方向获取UI对象&#xff0c;通知对象被点击/// </summary>public class VRInputMod…

在C语言基础上学Java【Java】【一】

众所周知&#xff0c;Java是C风格的语言&#xff0c;对于学过C语言的人学Java可以快速适应。 废话不多说&#xff0c;直接边看代码边学。 数据类型&#xff0c;输入和输出 import java.util.Scanner;//为了使用Scanner public class a1 {//a1是类名&#xff0c;就是文件名&am…

嵌入式硬件篇---WIFI模块

文章目录 前言一、核心工作原理1. 物理层&#xff08;PHY&#xff09;工作频段2.4GHz5GHz 调制技术直接序列扩频正交频分复用高效数据编码 2. 协议栈架构MAC层Beacon帧4次握手 3. 核心工作模式 二、典型应用场景1. 智能家居系统远程控制环境监测视频监测 2. 工业物联网设备远程…

一种很新的“工厂”打开方式---智慧工厂

随着信息技术的不断进步&#xff0c;特别是数字化、网络化、智能化技术的快速发展&#xff0c;传统的工厂管理模式已经难以满足现代企业对于生产效率、安全管理以及决策支持等方面的需求&#xff0c;智能制造已成为全球制造业发展的主流趋势。 由于工厂实时数据的多样性、复杂性…

Swagger2 使用教程

Swagger2 使用教程 Swagger&#xff08;现称为 OpenAPI Specification&#xff09;是一套用于描述、生成、消费和可视化 RESTful 风格 Web 服务的工具和规范。Swagger 2 是 OpenAPI 规范的一个重要版本&#xff0c;广泛应用于 API 的设计、文档化、测试和客户端代码生成。本文…

私域电商的进化逻辑与技术赋能:基于开源AI大模型与S2B2C商城的创新融合研究

摘要&#xff1a;本文基于私域电商"人格域品牌域直播电商"的三维架构&#xff0c;探讨开源AI大模型、AI智能名片、S2B2C商城及小程序源码等技术在私域流量运营中的创新应用。通过解析技术赋能路径与小米生态链等典型案例&#xff0c;揭示私域电商作为未来商业基础设施…

赛逸展2025创新模式,以科技创新奖赋能展位战略价值

CES Asia2025第七届亚洲消费电子技术贸易展&#xff08;赛逸展&#xff09;主办方负责人提出的创新理念&#xff0c;为展会的战略价值注入了新活力&#xff1a;“我们不是在卖展位&#xff0c;而是在分发政策红利入场券——企业每平方米的展位投入&#xff0c;都可能通过科技创…

【QA】观察者模式在QT有哪些应用?

1. 信号与槽机制 Qt的**信号与槽&#xff08;Signals & Slots&#xff09;**是观察者模式的典型实现&#xff0c;通过元对象系统&#xff08;Meta-Object System&#xff09;实现松耦合通信。 核心特点&#xff1a; 类型安全&#xff1a;编译时检查参数匹配跨线程支持&…