Go语言中的常见陷阱

最全的Go按照开发流程 Go是2009年开源的编程语言,Go语言具有以下特性:语法简洁、并发编程、编译迅速、数组安全、丰富的内置类型、错误处理、匿名函数和闭包、反射、函数多返回值、自动垃圾回收。**Go语言标识符与其它语言类似,第一个字符必须是字母、下划线,不能是数字。2、关键字Go语言的25个关键字或者保留字:Go语言的36个预定义标识符: 阅读详情

原文:Common Gotchas in Go
作者:Mike JS. Choi
翻译:雁惊寒

摘要:本文介绍了Go初学者很可能会遇到的三个常见陷阱。以下是译文。

我最近开发了我的第一个真正的Go程序。它叫“Fix All Conflicts(译者注:修复所有的冲突)”,或简称为fac。这是一个简单易用的控制台程序,用于解决git合并冲突。我之所以开发这么个工具,是因为我一直都没有找到一个好用的合并工具。

开发的过程非常有意思,我在这个过程中学到了很多东西。所以,我决定记录下初学者很可能会遇到的一些常见“陷阱”!

有时候,地鼠很可能相当有侵略性。

1. Range

range函数是Go中最常用的函数之一。下面是range函数的使用示例。请注意,基于一些疯狂的原因,我们决定让动物园里所有的动物都拥有999条腿。

type Animal struct {
    name string
    legs int
}

func main() {
  zoo := []Animal{ Animal{ "Dog", 4 },
                   Animal{ "Chicken", 2 },
                   Animal{ "Snail", 0 },
                 }

  fmt.Printf("-> Before update %v\n", zoo)

  for _, animal := range zoo {
    // Oppps! `animal` is a copy of an element
    animal.legs = 999
  }

  fmt.Printf("\n-> After update %v\n", zoo)
}

上面的代码看起来没什么问题。但是,你可能会惊讶地发现两个fmt.Printf()语句打印出来的结果是相同的。

-> Before update [{Dog 4} {Chicken 2} {Snail 0}]
-> After update [{Dog 4} {Chicken 2} {Snail 0}]

教训

range的value属性(这里是animal)是zoo的值的一个副本,而不是指向zoo中的值的指针。

修复

要修改数组中元素的值,我们必须通过它的指针来修改。

for idx, _ := range zoo {
  zoo[idx].legs = 999
}

这个看起来可能很平常,但你可能会惊讶地发现这是最常见的错误之一。

2. The … thingy

你可能会在C语言中使用…关键字来创建变长参数函数, 变长参数函数接受数量或类型可变的参数。

在C语言中,你必须调用va_arg宏来访问可选参数。如果用其他方式来使用可变参数,编译器就会报错。

int add_em_up (int count,...) {
  ...
  va_start (ap, count);         /* Initialize the argument list */
  for (i = 0; i < count; i++)
      sum += va_arg(ap, int);   /* Get the next argument value */
  va_end (ap);                  /* Clean up */
  return sum
}

然而,在Go中,情况有点相似,但又有很大的不同。下面是Go中的一个可变参数函数myFprint。请注意它是如何使用可变参数a的。

func myFprint(format string, a ...interface{}) {
    if len(a) == 0 {
        fmt.Printf(format)
    } else {
        // ⚠️ `a` should be `a...`
        fmt.Printf(format, a)
        // ✅
        fmt.Printf(format, a...)
    }
}

func main() {
    myFprint("%s : line %d\n", "file.txt", 49)
}
[file.txt %!s(int=49)] : line %!d(MISSING)
file.txt : line 49

你可能会认为编译器会因为我们错误地使用了可变参数a而报错。但是,请注意,fmt.Sprintf只是用了a中的第一个参数。

教训

在Go中,可变参数函数会被编译器转换成slices

这意味着可变参数a实际上只是一个slice。正因为如此,下面的代码是完全正确的。

// `a` is just a slice!
for _, elem := range a {
    fmt.Println(elem)
}

修复

记住,在使用可变参数的地方,请输入三个点(…)!

3. Slicing 切片

如果你了解Python中的slicing的话,你应该会知道Python中的slicing其实是给了你一个新的列表,该列表中的元素是对复制过去的元素的引用。因此,Python的代码是这样的。

a = [1, 2, 3]
b = a[:2]           # �� 完全是一个新的list
b[0] = 999
>>> a
[1, 2, 3]
>>> b
[999, 2]

但是,如果你在Go中编写同样的代码的话,就会遇到其他问题。

func main() {
  data := []int{1,2,3}
  slice := data[:2]
  slice[0] = 999

  fmt.Println(data)
  fmt.Println(slice)
}

教训

在Go中,切片与原始片共享相同的数组空间及其容量。因此,如果更改切片中的元素,也会改变原始数组中的内容。

修复

如果你想得到一个单独的切片,有两个选择。

// Option #1
// appending elements to a nil slice
// `...` changes slice to arguments for the variadic function `append`
a := append([]int{}, data[:2]...)

// Option #1
// Create slice with length of 2
// copy(dest, src)
a := make([]int, 2)
copy(a, data[:2]

根据StackOverflow中的一篇文章所述,append的速度比make. + copy更快一些。

1月13日,SDCC 2017之数据库线上峰会即将强势来袭,秉承干货实料(案例)的内容原则,邀请了来自阿里巴巴、腾讯、微博、网易等多家企业的数据库专家及高校研究学者,围绕Oracle、MySQL、PostgreSQL、Redis等热点数据库技术展开,从核心技术的深挖到高可用实践的剖析,打造精华压缩式分享,举一反三,思辨互搏,报名及更多详情可点击此处查看。
这里写图片描述

Go语言全面解析:从入门到精通 Go语言是由Google开发的一种静态类型、编译型编程语言,具有简洁、高效、安全的特点。它特别适合高并发服务、云原生应用和网络编程等场景。Go采用Goroutine和Channel实现轻量级并发,性能接近C/C++。与其他语言相比,Go语法更简洁但类型更严格,编译速度快且跨平台支持好。虽然Go支持多种设计模式和编程范式,但其面向对象实现方式与传统语言不同。标准库丰富且拥有Gin、GORM等企业级框架。核心语法包括包管理、变量声明、函数定义、流程控制等,适合构建高性能后端服务和系统工具。 阅读详情

相关推荐

Go语言的经典陷阱:理解后端开发中的常见问题

通过对这些常见的陷阱有所了解,并采取适当的预防措施,我们可以更好地编写高质量的Go后端代码。然而,这些只是一些常见问题的示例,实际开发中可能还存在其他陷阱。因此,在编写代码时,始终保持警惕,并且根据具体情况采取适当的措施来确保代码的正确性和可靠性。然而,即使对于有经验的开发人员来说,仍然存在一些常见的坑需要小心。希望本文能够帮助您更好地理解Go语言后端开发中的常见问题,并为您的开发工作带来帮助。如果您有任何疑问或需要进一步的帮助,请随时提问。在上述代码中,我们在循环中创建了多个匿名的goroutine。

BfuPhp的博客 137

Go学习笔记(四)

channel 关闭导致的问题 因为向关闭的channel 中传递数据导致 panic, 代码如下: func GetToken(ctx context.Context) (t string, err error) { ctxTimeout, cancel := context.WithTimeout(context.TODO(), 500*time.Millisecond) defer cancel() var token string signal := make(chan struct{}

SECURE2的博客 297

【go从入门到精通】闭包和陷阱

高科,先后在上一篇文章当时写完,总是感觉意犹未尽,从匿名函数我联想到了另外一个用法————闭包。

yolo模型训练找我,AI游戏合作找我 8万+

Go语言详解

Go(The Google Programming Language)语言是谷歌2009年发布的第二款开源编程语言。Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。Go支持面向对象,而且具有真正的闭包(closures)和反射 (reflection)等功能。 特色 简洁 快速 安全 并行 有趣 ...

顺其自然~专栏 3万+

基于图神经网络的社交网络虚假账号检测系统 (Graph-based Fake Account Detection System, GFADS)

FOLLOWSRETWEETSSHAREDCOMMENTSLIKESMENTIONSUseruser_idusernamejoin_datebioavatar_urllocationverifiedis_fakeLOAD CSV这是决定模型性能的关键环节,需结合和。XXedge_indexy新账号缺乏历史数据和丰富关系。全网图可能包含数亿节点和数十亿边,难以直接训练。社交网络是动态变化的,虚假账号策略也在不断进化。获取大规模、高质量的真实/虚假账号标注数据非常困难。

Deng945201314的博客 1481

微信聊天记录数据库解密实战:从WCDB到sqlcipher4的关键步骤解析

本文详细解析了微信桌面版聊天记录数据库的解密实战过程。通过逆向分析,定位了微信从WCDB框架到sqlcipher4加密的关键步骤,并成功提取了数据库密钥。文章重点介绍了如何通过动态调试、字符串定位等方法,追踪并验证sqlcipher4的加密密钥,最终实现对加密数据库文件的解密操作,为安全研究和数据恢复提供了技术参考。

weixin_29322553的博客 1071

Go语言超全详解(入门级)

Go语言是谷歌2009年发布的第二款开源编程语言(系统开发语言),它是基于编译、垃圾收集和并发的编程语言。 Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美 C / C++代码的速度,而且更加安全、支持并行进程......

weixin_50941083的博客 14万+

SpyGlass CDC实战:如何用sgdc约束文件解决跨时钟域报错(附常见错误排查)

本文详细介绍了如何使用SpyGlass CDC工具编写sgdc约束文件解决跨时钟域(CDC)报错问题。从基础语法到实战案例,涵盖时钟声明、复位约束、路径豁免等关键技巧,特别针对SPI断续时钟等特殊场景提供解决方案,并附常见错误排查指南,帮助工程师高效完成CDC验证。

weixin_28744423的博客 626

Go 语言中的 Slice 陷阱:如何避免常见错误

`Go` 语言提供了很多方便的数据类型,其中包括 `slice`。然而,由于 `slice` 的特殊性质,在使用过程中易犯一些错误,如果不注意,可能导致程序出现意外行为。本文将详细介绍 使用 `slice` 时易犯的一些错误,帮助读者更好的使用 `Go` 的 `slice`,避免犯错误。

cmy_top的博客 839

开发者的避坑指南:在Apple Silicon Mac上构建RocketMQ Python客户端的完整心路历程

本文详细记录了在Apple Silicon Mac上构建RocketMQ Python客户端的完整过程,重点解决了架构兼容性问题。通过源码编译rocketmq-client-cpp库,修复构建脚本和CMake配置,最终成功在M2芯片MacBook Pro上部署RocketMQ Python客户端,为开发者提供了实用的避坑指南。

Pepper的专栏 696

HyperMesh 2025新功能尝鲜:用Volume Tetramesh一键生成工业级四面体网格

HyperMesh 2025推出的Volume Tetramesh功能,通过“体到体”的全新范式,实现了工业级四面体网格的一键生成。该功能利用Proximity与Curvature参数智能识别并加密几何特征,将工程师从繁琐的几何清理和表面网格划分中解放出来,在保证网格质量的同时,显著提升了前处理效率,尤其适用于发动机缸体等复杂模型的仿真分析。

weixin_29229055的博客 477

十个Go语言开发中的常见陷阱与规避策略

Go语言的设计哲学强调简洁和明确,但这并不意味着开发者可以忽视代码中的潜在问题。本文讨论的十大常见错误涵盖了变量作用域、并发管理、数据结构操作、错误处理、资源管理等多个关键领域。要避免这些错误,开发者需要深入理解Go语言的特性及其背后的原理。变量隐藏问题要求我们对作用域有清晰的认识;goroutine泄漏防范需要我们对并发生命周期有全面规划;切片行为理解要求我们明白数据结构的底层实现;字符串连接优化则需要我们关注性能细节。

jike007gt的博客 987

深入解析安卓性能分析工具systrace/atrace的使用技巧与实战场景

本文深入解析了安卓性能分析工具systrace/atrace的核心使用技巧与实战场景。文章澄清了环境搭建的常见误区,详细拆解了命令参数,并通过列表卡顿、启动优化等具体案例,手把手指导开发者利用这些工具精准定位性能瓶颈,提升应用流畅度。

yyy34的博客 240

Go语言中的并发编程:最佳实践与常见陷阱

使用context:使用context控制goroutine的生命周期及时关闭channel:避免goroutine泄漏使用WaitGroup:等待多个goroutine完成并发编程是Go语言的核心特性,合理的并发编程能提高程序的性能和可靠性。作为一个务实的后端开发者,我建议关注并发编程的各个方面,从最佳实践到常见陷阱,不断优化并发代码。记住:并发编程不是银弹,它需要谨慎使用,避免常见陷阱。我见过不少团队,对并发编程不够重视,结果导致程序性能低下,甚至出现竞态条件。

好代码自己会说话,烂代码才需要注释来圆谎 3140

微信小程序 - 最新详细实现调起手机摄像头拍摄身份证人像面和国徽面取景框功能,在拍照相机上增加身份证证件照的轮廓或自定义文字,支持替换扫描拍摄辅助线图片及文本,小程序实现拍照身份证时带取景轮廓框拍摄!

微信小程序,身份证,证件照,人像,证件照提示框模板,vue身份证拍照框,摄像机相机里有引导内容,取景框拍摄,微信小程序实现拍照界面自定义实现,自拍人相框拍摄,取景框,户口簿取景框,画布指定区域生成图片,微信小程序身份证正反面拍照如何加入辅助图片引导照片,身份证取景框拍摄,服务器,上传,正反面,调起手机摄像头: 拍摄身份证的正反面,自定义身份证取景框,在相机上绘制 “身份证轮廓“ 与提示文字,拍摄身份证时出现人像框怎么实现,在相机上增加图片和文字,微信小程序怎么给调起的相机加入自定义图片,小程序实现给相机上面

🏆 前端领域优质创作者 3404

C#实现低通和高通滤波算法

低通滤波器允许通过低于某个截止频率的信号成分,并且抑制高于该频率的成分。而高通滤波器则允许通过高于某个截止频率的信号成分,并抑制低于该频率的成分。巴特沃斯滤波器是一种对称的滤波器,具有平坦的幅度响应和最小的群延迟。低通和高通滤波是数字信号处理中常用的滤波技术,用于滤除或增强信号中的特定频率成分。在本篇文章中,我们将使用C#编程语言来实现低通和高通滤波算法。以上就是使用C#实现低通和高通滤波算法的示例代码。你可以根据自己的需求调整截止频率和采样率,将这些代码应用于你的项目中。是滤波器的截止频率,

XisVisual_Basic的博客 1275

Go语言死锁检测终极指南:如何避免并发编程中的常见陷阱

Go语言以其卓越的并发编程能力而闻名,但并发编程中一个最棘手的问题就是**死锁**。当所有goroutine都被阻塞且无法继续执行时,程序就会陷入死锁状态。幸运的是,Go语言运行时内置了强大的死锁检测机制,能够自动检测并报告死锁情况。本文将深入探讨Go语言死锁检测的工作原理、常见死锁场景以及如何避免这些陷阱。 ## 什么是死锁?为什么它如此危险? 死锁是指两个或多个goroutine在等待对方

gitblog_00512的博客 1027

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Go 面试每天一篇(第 101 天)

点击上方蓝色“Golang来啦”关注我哟加个“星标”,天天 15 分钟,一起学 Go你好哇,欢迎来答题,一起来看下昨天题目的解析:1.下面代码输出什么? 1funcmain(){ ...

Seekload 203

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

go import 指定分支_Go语言的那些坑二

热烈欢迎你,相识是一种缘分,Echa 哥为了你的到来特意准备了一份惊喜,go学习资料《「转」go 语言实战笔记教程系列大纲汇总-值得收藏》目录:Go语言的那些坑Golang中函数被看做是值,函数值不可以比较,也不可以作为map的key请问以下代码能编译通过吗?import ("fmt")func main(){array := make(map[int]func ()int)array[func(...

weixin_42226397的博客 973

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Go 面试每天一篇(第 108 天)

点击上方蓝色“Golang来啦”关注我哟加个“星标”,天天 15 分钟,一起学 Go你好哇,欢迎来答题,一起来看下昨天题目的解析:1.下面代码输出什么?请简要说明。1funcmain(...

Seekload 191

Go 面试每天一篇(第 100 天)

点击上方蓝色“Golang来啦”关注我哟加个“星标”,天天 15 分钟,一起学 Go你好哇,欢迎来答题,一起来看下昨天题目的解析:1.下面代码能编译通过吗?1funcmain(){ ...

Seekload 221

美之为美golang杂记

Creek Shi 269

为什么Golang的switch设计需要fallthrough?从底层原理讲透这个特殊关键字

本文深入解析Golang中switch语句的`fallthrough`关键字设计原理与应用场景。从语言设计演变、编译器实现机制到典型应用与陷阱,揭示这一特殊语法在状态机实现、多重条件处理等场景的价值,同时强调其在工程实践中需谨慎使用以避免常见问题。

star的博客 187

Go 基准测试中的常见陷阱

【编者按】本文主要介绍在 Go 语言中进行基准测试的一些常见陷阱和误区。原文链接:https://eli.thegreenplace.net/2023/common-pitfalls-in-go-benchmarking/未经允许,禁止转载!作者 | Eli Bendersky 译者|明明如月责编 |夏萌出品 | 优快云(ID:优快云news)虽然 Go 语言标准库的 tes...

优快云资讯 707

golang-notes进阶指南:锁无关编程与原子操作的终极解决方案

在现代并发编程中,锁无关编程和原子操作是构建高性能Go应用程序的关键技术。本文将深入解析golang-notes项目中关于锁无关设计和原子内存操作的完整实现方案。 锁无关编程是一种并发编程范式,它通过原子操作来确保数据一致性,避免了传统锁机制带来的性能瓶颈。Go语言的sync/atomic包提供了强大的原子操作原语,让开发者能够编写出既高效又安全的并发代码。🚀 ## 什么是锁无关编程? 锁

gitblog_00898的博客 416

go语言常见陷阱

go语言常见陷阱(英文原文)[https://deadbeef.me/2018/01/go-gotchas]Range在golang中我们经常用range来遍历slice或chan,如果要更改slice中的成员应该怎么做?下面代码要把动物园中所有动物的腿变为999type Animal struct { name string legs int }func main() { zo

KingEasternSun的专栏 1527
上一篇: 2017年度盘点丨基础架构演化:从“以资源为中心”到“以应用为中心”的迁移
下一篇: 使用Java 9的模块化来构建零依赖的原生应用
csdn研发技术
博客等级 码龄9年 1381粉丝 90原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值