当前位置: 首页 > news >正文

Common Go Mistakes(Ⅲ 控制结构)

导航

  • 常见的 Go 错误
    • 引言
    • Ⅲ 控制结构
      • 30. 忽略 `range` 循环变量是一个拷贝
      • 31. 忽略 range 循环中迭代目标值的计算方式
      • 32. 忽略 range 循环中指针元素的影响
      • 33. map 迭代过程中的错误假设
      • 34. 忽略 break 语句如何工作
      • 35. 在循环中使用 defer

常见的 Go 错误

参考 100go

引言

  • 在循环中如何处理指针
  • break 语句

Ⅲ 控制结构

30. 忽略 range 循环变量是一个拷贝

这个问题是Go语言中range循环的一个常见陷阱:range循环中的元素是值拷贝,而不是引用

当使用range遍历切片或数组时,循环变量获得的是元素的副本,而不是原始元素的引用。如果试图通过循环变量修改元素,实际上只是修改了副本,原始数据不会改变。

示例代码

type User struct {Name stringAge  int
}func main() {users := []User{{"Alice", 25},{"Bob", 30},}// 错误示例:试图修改元素for _, u := range users {u.Age = u.Age + 1  // 只修改了副本,原数据不变}fmt.Println(users)  // 输出: [{Alice 25} {Bob 30}],没有变化
}

解决方案

方案1:使用索引访问原始元素

for i := range users {users[i].Age = users[i].Age + 1
}

方案2:使用指针切片

userPtrs := []*User{{"Alice", 25},{"Bob", 30},
}for _, u := range userPtrs {u.Age = u.Age + 1  // 通过指针修改原始数据
}

为什么会这样设计?

  • 值拷贝是Go语言的一致性设计,避免隐式的引用传递
  • 对于大结构体,这可能会有性能影响
  • 如果需要修改原始数据,应该明确使用索引或指针

31. 忽略 range 循环中迭代目标值的计算方式

在Go语言,range 关键字后面的表达式在循环开始之前,只会被求值一次,一旦循环开始,它遍历的是这个表达式在循环开始时所确定的值或状态。例如:

// 示例:arr 数组是 Range 表达式
arr := [3]int{1, 2, 3} for i, v := range arr { // arr 表达式只在循环开始前求值一次arr[2] = 99 // 在循环体内修改原始数组fmt.Printf("Iteration %d: v=%d\n", i, v)
}// 输出结果:
// Iteration 0: v=1
// Iteration 1: v=2
// Iteration 2: v=3

遍历不同的对象时有不同的表现,如下所示:

类型求值次数循环遍历的对象循环内修改原始集合的影响
Array (数组)一次数组的完整副本原始数组被修改,但循环不受影响。
Slice (切片)一次切片头的副本(指向原始底层数组)通过索引修改底层数组会生效,但循环变量 v 依然是旧值的副本。
Map (映射)一次映射的引用副本循环内删除元素有效;添加元素不保证被遍历

32. 忽略 range 循环中指针元素的影响

在range循环中,循环变量(如v)在每次迭代时会被重新赋值,但变量本身的内存地址不变。如果取这个变量的地址&v,所有指针都会指向同一个内存位置。

Go 1.22 之前的 for 循环迭代变量是 per-variable-per-loop 而不是 per-variable-per-iteration,才导致该问题。

Go 1.22+改进了这个问题,在这之后的版本不存在该问题。详见

33. map 迭代过程中的错误假设

在 Go 语言中,for range 循环遍历映射(map)时,容易产生以下错误的假设:

  • 映射会按照键的顺序(或插入顺序)进行遍历
  • 在迭代过程中添加的元素,会在当前循环中被遍历到
  • 每次遍历顺序相同的

34. 忽略 break 语句如何工作

在 Go 语言中,一个不带标签(Label)的 break 语句只能中断它所处的最内层的 for、switch 或 select 语句。代码如下:

package mainimport ("context""fmt"
)func listing1() {for i := 0; i < 5; i++ {fmt.Printf("%d ", i)switch i {default:case 2:break}}
}func listing2() {
loop:for i := 0; i < 5; i++ {fmt.Printf("%d ", i)switch i {default:case 2:break loop}}
}func listing3(ctx context.Context, ch <-chan int) {for {select {case <-ch:// Do somethingcase <-ctx.Done():break}}
}func listing4(ctx context.Context, ch <-chan int) {
loop:for {select {case <-ch:// Do somethingcase <-ctx.Done():break loop}}
}

35. 在循环中使用 defer

defer 语句是基于函数的,而不是基于循环的。 在循环中使用 defer 会导致资源(如文件句柄、锁、内存)得不到及时释放,引发资源泄漏或内存溢出(OOM)。

当在循环内部使用 defer 来处理资源(例如打开文件、获取数据库连接、申请锁)时,关闭动作必须等到整个函数退出时才会发生。
可以通过新建一个函数或使用匿名函数来解决该问题,例如:

package mainimport "os"func readFiles1(ch <-chan string) error {for path := range ch {file, err := os.Open(path)if err != nil {return err}defer file.Close()// Do something with file}return nil
}func readFiles2(ch <-chan string) error {for path := range ch {if err := readFile(path); err != nil {return err}}return nil
}func readFile(path string) error {file, err := os.Open(path)if err != nil {return err}defer file.Close()// Do something with filereturn nil
}func readFiles3(ch <-chan string) error {for path := range ch {err := func() error {file, err := os.Open(path)if err != nil {return err}defer file.Close()// Do something with filereturn nil}()if err != nil {return err}}return nil
}
http://www.dtcms.com/a/606992.html

相关文章:

  • vs建设网站营销的方法和技巧
  • 用vs2010做网站并连数据库2021ppt模板免费下载 素材
  • 【2025 最新】 Maven 下载安装与配置教程(超详细带图文Windows 版):从入门到实战
  • 做瞹视频网站哪里看志鸿优化设计官网
  • 南宁网站建设怎么样封开网站建设
  • 易语言exe反编译器 | 高效破解和安全分析工具
  • 智能决策系统落地后如何进行数据集成与安全保障?
  • 企业备案网站可以做论坛吗西安有哪些网站
  • 网站程序超市做网站怎样才能接单
  • 第三章 下一代防火墙通用原理
  • 57_AI智能体运维部署之实战指南:安装Docker Desktop的完整过程
  • 河南经天路桥建设总公司网站网站首页的名字通常是
  • 在上海做网站招商局网站建设管理总结
  • OpenAI GPT-5.1正式发布:智商情商双突破,开启AI交互新时代
  • 无需联网也能跨设备转写!CapsWriter+cpolar 实现隐私级语音协作
  • 建立网站考虑的三大要素安阳网站建设商祺
  • 辽宁专业模板网站建设公司工信和信息化网站备案系统
  • 高端网站设计哪个好商机创业网
  • 河源做网站优化线上平面设计培训班
  • 从概念到实践:解锁 CrewAI 多智能体协作的强大潜能
  • wordpress后台模板位置益阳seo网站建设
  • 灵台县住房和城乡建设局网站谷歌外贸平台有哪些
  • 公司门户网站建设方案网站可以做砍价软件吗
  • qq推广网站北京公司网站设计价格
  • 如何使用图片素材快速生成一个卡片类型的博客页面:从需求到实现的完整指南
  • 网站建设的工作wordpress适配熊掌号
  • 网站开发和合同范本二维码设计软件
  • 关于网站关停的申请企业网站怎么扣费的
  • 非安防领域调试心得-兼顾收敛速度和过渡平滑效果的一些优化措施
  • asp网站后台密码破解项目名称