golang踩坑 2.goroutine闭包和遍历字符串字符

GO语言基础教程(41)Go循环语句之for-range循环:Go语言for-range循环:遍历数据的瑞士军刀 Go语言中的for-range循环是遍历各类数据结构的全能选手,它简洁高效但暗藏陷阱。本文带你深入探索for-range的妙用,从基本操作到底层原理,再到常见坑位解析,让你彻底掌握这把Go语言中的迭代利器,写出更优雅安全的代码。 阅读详情

我们都生活在阴沟里,但仍有人仰望星空。——奥斯卡王尔德

详细请点击微信公众号:golang踩坑 2.goroutine闭包和遍历字符串字符

1. 前言

这篇文章我们来聊聊在循环中使用Goroutine中捕获参数的问题和使用下标获取字符串的字符问题,这两个问题在项目中比较常见,大家记得要规避。

2. Goroutine中捕获参数

goroutine中捕获的循环变量, 都为循环最后的值。

func main() {

    for i, v := range []string{"a", "b", "c", "d", "e"} {
        // goroutine中捕获循环变量
        go func() {
            fmt.Printf("index: %v, value: %v\n", i, v)
        }()
    }

    // 此处应该使用waitgroup实现, 为了简单使用了sleep
    time.Sleep(1 * time.Second)

}

//================输出==============

index: 4, value: e
index: 4, value: e
index: 4, value: e
index: 4, value: e
index: 4, value: e

原因:

goroutine中捕获的不是"值", 而是"有地址的变量". for循环可能会先结束, 之后各个goroutine才开始执行. 因此得到的是变量的最终值。

避免方式 在goroutine启动的函数中, 把变量作为参数捕获。

func main() {

    for i, v := range []string{"a", "b", "c", "d", "e"} {
        // 把循环变量作为参数传入
        go func(i int, v string) {
            // i, v是函数内部的局部变量
            fmt.Printf("index: %v, value: %v\n", i, v)
        }(i, v)
    }

    time.Sleep(1 * time.Second)

}

//================输出==============

index: 0, value: a
index: 1, value: b
index: 4, value: e
index: 3, value: d
index: 2, value: c

3. 获取字符串的字符

使用下标获取字符串的字符时, 可能得到奇怪的字符

func main() {

    s := "hello"

    fmt.Printf("%c\n", s[1])

    s = "你好"

    fmt.Printf("%c\n", s[1])

}

//============输出===========

e
½

原因:

golang是以utf8格式保存字符串的, 字符串的下标操作, 访问的是字节, 而不是字符. len函数输出的也是字节数, 如len("hello")==5, len("你好")==6。

避免方式 把字符串转化为[]rune/[]int32, 或者使用range遍历

func main() {

    s := "你好"

    // 强转为[]rune
    fmt.Printf("%c\n", []rune(s)[1])

    fmt.Println()

    // 使用range遍历
    for _, c := range s {
        fmt.Printf("%c\n", c)
    }

}

//===============输出=================

好

你
好

4. 小结

针对循环创建goroutine获取外面参数这种闭包问题记得一定要小心,根据实际情况做出调整。当然循环根据下标获取字符串字符也会有问题,一定小心谨慎对待。

5. 关注公众号

微信公众号:堆栈future

希望大家关注哈,原创不容易,求点赞,求关注,求分享

扫码_搜索联合传播样式-标准色版.png

Go 学习笔记(29)— range 作用于字符串、数组、切片、字典、通道 1. 使用说明 range 应用于不同数据类型时,类似迭代器操作,返回 (索引, 值) 或 (键, 值)。 下表是对应的结构: type 1st value 2nd value string index s[index] array/slice index s[index] map key m[key] channel element 2. 使用示例 如果想忽略不想要的值时,可以使用 “_” 这个特殊变量。 package main func main() { s := 阅读详情

相关推荐

freeswitch之呼叫中心acd模块开发

一、定义: ACD(Automatic Call Distributor) 自动呼叫分配,也叫智能选择座席。它是呼叫中心整个前台接入系统逻辑功能的描述:把接入的呼叫转接到正确的座席员桌前。ACD是现代呼叫中心有别于一般的热线电话系统和自动应答系统的重要标志,其性能的优劣直接影响到呼叫中心的效率和顾客的满意度。 二、ACD包含的功能点: 1 、程控交换功能 ACD在本质上也是交换机的一种类型,必须具有程控交换最基本的话务交换功能。 2 、排队功能 ACD必须具有话务排队的功能,所谓排队是指在内线都

飞鸟的博客 1870

golang的for和闭包与goroutine使用中的坑

go func 并不能保证立即执行,在它还没有执行的时候,item值已经被for循环改变了。 正确代码: package main import ( "fmt" "sync" ) func main() { var s []string = []string{ "1", "2", "3", } var waitGroup sync.WaitGroup waitGroup.Add(len(s)) for _, item := range s { go fun.

仅做个人笔记 1106

C语言图形化界面——含图形、按钮、鼠标、进度条等部件制作(带详细代码、讲解及注释)

本文借助easyx库函数(提供下载链接),很方便地用C语言实现了鼠标、按钮、进度条、坐标尺等操作,为普通C程序的友好人机交互界面提供了一种简单便捷的方案。

体会编程语言独到的美 17万+

golang闭包里的坑

介绍 go的闭包是一个很有用的东西。但是如果你不了解闭包是如何工作的,那么他也会给你带来一堆的bug。这里我会拿出Go In Action这本书的一部分代码,来说一说在使用闭包的时候可能遇到的坑。全部的代码在github上。   闭包的坑 首先看一段代码: search/search.go 29 // Launch a goroutine for each feed to f

future_challenger的专栏 3290

解密DS90UB983-Q1的汽车电子魔法:如何通过FPD-Link IV实现4K视频的无缝传输

本文深入解析了德州仪器DS90UB983-Q1串行器芯片如何通过FPD-Link IV技术在汽车电子中实现4K视频无缝传输。文章详细介绍了该技术的核心功能,包括多流传输(MST)模式、热插拔检测(Hot Plug Detect)机制以及电磁兼容性设计,为车载信息娱乐系统提供了高带宽、低延迟的可靠解决方案。

i3j4k5的博客 240

Claude Code 完整使用教程(2026最新版)

《Claude Code 完整使用教程(2026最新版)》摘要: Claude Code 是 Anthropic 公司推出的智能编程工具,通过自然语言对话实现代码编写、调试和重构。本教程基于 v2.1.101 版本,涵盖安装配置、核心功能及最新特性。主要内容包括: 多平台安装方式(macOS/Linux/Windows) 桌面应用专属功能如并行会话、定时任务和语音模式 模型选择指南(Sonnet/Opus/Haiku) 快速入门示例:5分钟创建Node.js项目 核心功能:代码读写、命令执行、Git集成等

程序猿_三产 2万+

go for range坑和闭包坑

看程序: package main import ( "fmt" "time" ) func main() { str := []string{"I","like","Golang"} for _, v := range str{ v += "good" } for k, v := range str{

认知 行动 坚持 6425

第三篇:学习InternVL2.0(探讨代码之训练模块版)

InternVL2的训练模块

qq_69051120的博客 1244

Go语法:闭包

闭包在 Go 语言中是一把 "双刃剑":它能便捷捕获外部变量,却也常因变量引用机制导致意外行为,尤其在循环与多协程场景中容易引发数据混乱。理解闭包的变量捕获逻辑,掌握副本创建技巧,是写出安全可靠代码的关键。:goroutine 启动时可能循环已经执行完毕,所有 goroutine 都访问到最终的。的值为 3,所以所有函数调用都输出 3。:在每次循环中创建一个局部变量副本。:所有闭包都引用了同一个变量。:通过参数传递当前值。

LanJieZhiFu的博客 518

如何理解Apollo模型参考自适应控制MRAC

最近有了解到百度无人驾驶Apollo项目中的横向控制有用到MRAC(Model Reference Adaptive Control),于是便详细研究了一下这个控制方法,在此总结一下心得。 什么是MRAC MRAC控制系统的基本结构图如下所示: 它由两个环路组成,由控制器和受控对象组成内环,这一部分称之为可调系统,由参考模型和自适应机构组成外环。实际上,该系统是在常规的反馈控制回路上再附加一个参考模型和控制器参数的自动调节回路而形成。在该系统中,参考模型的输出或状态相当于给定一个动态性能指标,(通常,参考模

zmhzmhzm的博客 6479

Debezium系列之:深入理解 Debezium Topic的设置要求

Debezium系列之:配置 Debezium Topic

zhengzaifeidelushang的博客 1009

两年经验斩获蚂蚁/头条/PingCAP Offer,牛逼哈!

“ 分享一篇面经,作者拿到了 PingCAP,今日头条的 offer 以及蚂蚁金服的口头 offer。下面是该作者的经验分享。 去年(18年)年底想出来看看机会,最后很幸运地拿到了 PingCAP,今日头条的 offer 以及蚂蚁金服的口头 offer。想着可以总结一下经验,分享一下自己这一段”骑驴找马”过的心路历程。当然,一家之言,难免粗浅,如有不妥,敬请指正。 全文有点长,假如只对一家公司感兴趣的话可以直接跳过去: 准备过程 面试: PingCAP 面试: 蚂蚁

勇往直前的专栏 1389

零基础学习CANoe Panel(5)——改变变量的值,控件图像也改变,这是怎么回事?

Panel 中控件的图像随着值变化,是怎么回事?

蚂蚁小兵 2145

Go语言一些容易踩坑的地方

1、可变参数是空接口类型 func main() { var a = []interface{}{1, 2, 3} fmt.Println(a) fmt.Println(a...) } 不管是否展开,编译器都无法发现错误,但是输出是不同的: [1 2 3] 1 2 3 2、数组是值传递 在函数调用参数中,数组是值传递,无法通过修改数组类型的参数返回结果,因此必要时使用切片 3、map遍历顺序不固定 map是一种hash表的实现,每次遍历的顺序可能都不一样 4、返回值被屏

Canger_的博客 742

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Go语言常见坑

但是Goroutine确存在泄漏的情况,同时泄漏的Goroutine引用的内存同样无法被回收。当main函数在break跳出循环时,通过调用cancel()来通知后台Goroutine退出,这样就避免了Goroutine的泄漏。在函数调用参数中,数组是值传递,无法通过修改数组类型的参数返回结果,切片是地址传递,必要时需要使用切片。当内存发送变化的时候,相关的指针会同步更新,但是非指针类型的uintptr不会做同步更新。当参数的可变参数是空接口类型时,传人空接口的切片时需要注意参数展开的问题。

wqeffort的博客 793

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Golang学习中遇到的问题

不断踩坑,持续更新。 这里包含两个部分 亲身经历:自己遇到的问题,包括踩的坑,模糊的知识点,不能瞬间想到的问题等等。 他人经验:看他人的博文发现的问题,会收在第二部分中,如果有一天想通了会放到第一部分。 亲身经历: 切片初始化 slice := make([]type, len) 用make创造切记len参数不能省略 切片append添加的是单个元素不是切片 ...

Lazyboy_的博客 726

Go面试高频考点全解析:数组、切片、Map、接口与闭包一次搞懂(Backend-NodeJS-Golang-Interview_QA)

**Go面试高频考点**到底考什么?数组、切片、Map、接口与闭包,几乎是每一场 Golang 后端面试都绕不开的"必答题"。本文基于开源项目 Backend-NodeJS-Golang-Interview_QA(一份收录了 Node.js 与 Golang 后端高频面试题的开源问答集),把这些知识点掰开揉碎讲清楚——不堆代码、不说黑话,让零基础新手也能快速建立起 Go 面试的知识框架,从容应对面

gitblog_00830的博客 530

golang byte转file对象_Golang 常见的坑

这里列举的Go语言常见坑都是符合Go语言语法的,可以正常的编译,但是可能是运行结果错误,或者是有资源泄漏的风险。1、可变参数是空接口类型当参数的可变参数是空接口类型时,传人空接口的切片时需要注意参数展开的问题。func main() { var a = []interface{}{1, 2, 3} fmt.Println(a) fmt.Println(a...) }不管...

weixin_35643153的博客 1287

Golang学习手册

安装非常简单,直接默认安装就行;最新版的不需要到windows的电脑属性中去设置GOPATH 安装成功后,在cmd下设置 // 默认GO111MODULE 是关闭的 go env -w GO111MODULE=on 新建项目的开发目录,如在d:\golang下面新建的项目文件夹,每个文件夹就属于一个项目 // d:\golang mkdir firstDemo cd firstDemo // 通过go mod 来管理 go mod init firstDemo // 会在当前下面生成go.mod 文件

book_longker的专栏 5809

golang学习之七:for 语句的常见“坑”与避坑方法

1.凡是用到for-range的地方一定要小心2.凡是用到闭包的地方,参数取值或传参一定要小心3.go方法的本质,也就是 一个以方法的receiver参数作为第一个参数的普通函数4.for-range的时候,如果调用闭包千千万万要看清在将函数注册到函数栈上时有没有注册参数:若有:则注意参数的类型是指针还是非指针。若没有:那么函数运行时,就找闭包函数之外的变量运行了,注意此时变量的值。

java_xxxx的博客 1931

go学习:特殊之处、语言特性

背景 学习一门新语言,其实大多数东西都是类似的,我们只需要关注这么语言特殊的地方。本文就是在学习过程中记录go特殊的地方 特殊之处 闭包 b站 git_book vscode 搭建环境 defer 把语句放到栈中,函数结束的时候再执行 一般用于打开文件/数据库后立马defer 关闭,有点像把finally提前 package main import ( _ "encoding/json" "fmt" ) func sum(n1 int, n2 int) int { defer fmt.Prin

stevewong的专栏 302

Go学习总结

go学习笔记 包初始化 初始化顺序init函数特点go语言字符串 go语言直接使用utf8编码,所以不像其他某些语言,需要将文件转成unicode码存储在内存中。而是直接使用utf8码进行操作。最后两种需要转换类型,要进行复制,不建议使用。 4.字符串和数字转换 将数字转换成字符串 字符串转换整数 Go语言interface go语言的接口是实现是解耦合的。当一个结构实现了接口的所有方法,我们就认为这个结构实现了这个接口。原来的c++和java需要先定义接口,再去实现。go可以先实现方法,再去想

wayne_H3的博客 1454

Go by Example / Golang入门教程(非常详细)

转载:https://gobyexample.com/ Go by Example Gois an open source programming language designed for building simple, fast, and reliable software. Go by Exampleis a hands-on introduction to Go u...

Flyer的后花园 2802

Go二进制逆向必懂知识:从pclntab到moduledata,解密golang_loader_assist的运行时结构

拿到一个被剥离符号的 Go 二进制,很多安全研究员都会头疼:Go二进制逆向与传统的 C/C++ 逆向完全不同,没有熟悉的 libc 运行时结构,函数名全部丢失,连 IDA Pro 的自动分析也频繁"罢工"。而 golang_loader_assist 正是为解决这一痛点而生的开源 IDA Pro 辅助插件:它通过解析 pclntab、moduledata 等 Go 运行时结构,自动恢复函数名、还原

gitblog_00028的博客 368

Go语言入门详细教程

Go语言最初由Google公司的Robert Griesemer、Ken Thompson和Rob Pike三个大牛于2007年开始设计发明,他们最终的目标是设计一种适应网络和多核时代的C语言。所以Go语言很多时候被描述为“类C语言”,或者是“21世纪的C语言”,Go 富有表现力、简洁、干净且高效。其并发性机制使编写充分利用多核的程序变得容易,而其新颖的类型系统可实现灵活和模块化程序构建。Go 可以快速编译为机器代码,且具有垃圾回收的便利性和运行时反射的强大功能。是一个快速的静态类型的编译语言,但感觉就像动

m0_53328239的博客 5337

go select 和for_Go语言常见坑

Go语言常见坑这里列举的Go语言常见坑都是符合Go语言语法的,可以正常的编译,但是可能是运行结果错误,或者是有资源泄漏的风险。可变参数是空接口类型当参数的可变参数是空接口类型时,传入空接口的切片时需要注意参数展开的问题。func main() { var a = []interface{}{1, 2, 3} fmt.Println(a) fmt.Println(a......

weixin_29304713的博客 435
上一篇: golang踩坑 1.slice传参和for range赋值
下一篇: golang踩坑 3.接口值是否等于nil
stackfuture
博客等级 码龄5年 23粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值