Go语言中常见100问题
文章平均质量分 81
golang学习笔记
数据小冰
好记性不如烂笔头,学习、实践、总结,成为更好的自己。
展开
-
Go语言必知必会100问题-24 如何正确的对切片进行拷贝
内置的 copy 函数实现了将源切片中的数据拷贝到目标切片中的功能,尽管这是一个常用的内置函数,但是还是有不少开发者使用有误。总结,将一个切片中的元素拷贝到另一个切片是一种非常频繁的操作,当我们使用copy函数时,需要记得拷贝的元素个数是源切片和目标切片中长度较短的。copy函数将源切片中的数据拷贝到目标切片时,拷贝的元素个数为下面两个长度中较小的一个。在前面的代码中,源切片src的长度为3,但是目标切片dst的长度为0,因此,调用copy函数拷贝的元素个数为0,所以打印输出为空切片。原创 2024-03-13 22:23:40 · 430 阅读 · 0 评论 -
Go语言必知必会100问题-23 判断空切片最佳方法
在Go语言必知必会100问题-22 空切片与nil切片有区别吗?中分析了空切片和nil切片是有区别的,那如何正确的判断一个切片是否为空切片呢?综上,我们并不是总能够修改调用方逻辑,所以通过判断切片的长度是否为0判别切片中是否存在元素是最佳方法。与此同时,正如Go wiki中陈述的,在我们设计接口的时候,应该避免区分空切片和nil切片,对它们做区分会导致细微的程序错误。在返回切片时,如果返回nil切片或空切片,要确保不会产生语义上和技术上的差异,两者表达的应该是同一个意思。原创 2024-03-13 22:16:18 · 400 阅读 · 0 评论 -
Go语言必知必会100问题-22 空切片与nil切片有区别吗?
nil切片与nil相等,空切片的长度为0,但是它不等于nil。如果能够确定最后返回的切片为空,则推荐使用 var s []string, 如果在初始化时已知道切片的长度,则采用make([]string,length)最好,[]string(nil)提供了一种语法糖,方便添加元素操作。剩余未讨论的方法2 s:=[]string(nil)和方法3 s:=[]string{}中,方法2使用的最不广泛,只是可以用作语法糖,因为我们可以在一行代码中完成定义一个nil切片并完成元素添加操作,示例程序如下。原创 2024-03-12 22:09:50 · 651 阅读 · 0 评论 -
Go语言必知必会100问题-21 切片初始化方法及最佳实践
总结,将一种切片类型转换为另一种切片类型是Go中经常遇到的操作。通过前面的分析,如果提前已知道切片的长度是多少,就不要创建一个大小为0的空切片,采用分配给定容量或给定长度对切片进行初始化是最佳选择。具体是采用给定容量还是给定长度,要根据实际情况进行选择,采用给定容量代码的可阅读性更好,采用给定长度程序的性能往往更高。原创 2024-03-12 22:07:03 · 1048 阅读 · 0 评论 -
Go语言必知必会100问题-20 切片操作实战
有很多gopher将切片的length和capacity混淆,没有彻底理清这两者的区别和联系。理清楚切片的长度和容量这两者的关系,有助于我们合理的对切片进行初始化、通过append追加元素以及进行复制等操作。如果没有深入理解它们,缺少高效操作切片的方法,甚至可能导致内存泄露。切片长度是切片中已有元素的数量,而切片容量是切片中可以容纳的元素数量。向切片中添加元素,当长度和容量相等时会导致创建具有新容量的新底层数组,复制所有来自前一个数组的元素,并将切片指针更新为新数组。原创 2024-03-10 18:17:47 · 1061 阅读 · 0 评论 -
Go语言必知必会100问题-19 浮点数溢出问题
Go语言中float32和float64在计算机中是一种近似值表示,因此,我们必须牢记下面的规则:当比较两个浮点数时,检查它们的差值是否在可接受的范围内,而不是直接 == 进行比较当执行加法或减法时,为了获得更好的精度,可以根据运算级进行分组为了提高准确性,如果一系列运算需要加法、减法、乘法或除法,先执行乘法和除法运算。原创 2024-03-10 18:09:01 · 1072 阅读 · 0 评论 -
Go语言必知必会100问题-18 忽略整数溢出
判断两个整数相乘的结果是否存在溢出有点小复杂,需要检查相乘的整数是否有值为math.MinInt. 如果乘数a或b一个为0,则结果为0.如果a或b有一个为1,则结果为a或b.如果a或b为math.MinInt,则会存在下溢,如果result/b!除了上面的8种类型,还有两种整数类型是:int和uint,这两种类型的大小取决于系统,在32位操作系统上,int/uint类型为32 bits,在64位系统上,int/uint类型为64 bits.但是在运行时,整数上溢和下溢是无感知的,不会导致应用程序崩溃。原创 2024-03-09 17:29:15 · 781 阅读 · 0 评论 -
Go语言必知必会100问题-17 进制混淆
八进制整数在不同的场景中很有用,例如,假设我们想要使用 os.OpenFile 打开一个文件,该函数需要将权限作为 uint32 类型传递,如果我们想匹配linux文件权限,可以传递一个八进制数字而不是一个十进制数字。为了便于阅读,我们还可以使用下划线字符(_)作为分割符,例如,10亿可以这样表示:1_000_000_000. 此外,还可以将下划线字符与其它表示形式一起使用,像 0b00_00_01 表示的十进制数为1。二进制:使用 0b 或 0B 前缀,例如 0b100等于十进制中的4.原创 2024-03-09 17:26:09 · 316 阅读 · 0 评论 -
Go语言必知必会100问题-16 不使用 linter
linter和格式化程序是提高代码质量、保持代码风格一致的有力方法,我们应该花点时间了解如何使用它们,并且能够自动执行检查,例如将这些检查集成到CI或git提交钩子中,在提交代码前做风格检查等操作。本文内容不是列举通过linter检查出来的所有问题,而是通过个别例子来理解linter为什么重要,为什么对Go项目开发是必不可少的。由于vet已集成在标准库中,所以只需要安装shadow工具,安装方法如下,然后联合vet工具,对上面的代码进行检查,输出结果如下。正如上面看到的,vet工具提示我们变量i被遮蔽。原创 2024-03-08 22:25:03 · 477 阅读 · 0 评论 -
Go语言必知必会100问题-15 缺少代码文档
当对变量或常量进行注释说明时,我们可能想传递两方面内容:它的目的和内容. 变量或常量的目的应该作为代码文档存在,以便对外部使用者有所帮助。DefaultPermission 表示默认权限,代码文档注释说明了该变量的目的,而常量旁边的注释描述了它的实际内容(读写权限)。此外,当对一个函数(或方法)注释说明时,应该强调函数打算做什么,而不是它是如何实现的。通常,我们应该将包文档放在与包同名的相关Go文件中,或者放在特定文件中,如doc.go. 关于包文档,最后要说的一点是,与声明不相邻的注释会被省略。原创 2024-03-03 22:04:08 · 528 阅读 · 0 评论 -
Go语言必知必会100问题-14 忽视包名冲突
虽然上面这种做法非常直接有效,但是,如果出现某种原因我们更喜欢保留名为redis的变量,这时可以在导入包上做点文章,给导入包起一个别名,代码中使用包的别名可以避免冲突,示例程序如下。假设在一个函数中同时使用了变量redis和包名redis,在这种情况下,阅读代码的时候可能混淆不清。上述代码保存在redis库中,现在有一个客户端程序,使用到上面的redis包提供的功能。尽管调用的包名是redis,但在Go语言中创建一个名为redis的变量是完全有效的。当变量名与包名相同时会发生包冲突,会阻止包被重用。原创 2024-03-03 21:51:12 · 329 阅读 · 0 评论 -
Go语言必知必会100问题-13 创建util包不是一种好的做法
在Go语言中完成该功能的惯用方法是通过 map[K]struct{} 类型来处理,K是map中允许的任何类型作为键,而值是 struct{} 类型, 表示我们对值不关心。上述代码的问题是包名 util 没有任何意义,我们可以称它为 common、shared 或 base, 但它仍是一个毫无意义的名称, 无法提供任何关于包的有意义信息。程序包的命名是应用程序设计的一个关键点,我们应该对此保持谨慎。我们可以对上面的程序做进一步封装,创建一个特定的类型并将Sort作为对外提供的方法,而不是一个对外公开的函数。原创 2024-03-02 18:47:49 · 438 阅读 · 0 评论 -
Go语言必知必会100问题-12 如何设计项目结构
Go语言维护者对构建Go项目结构没有严格的约定,在github上有一个称为标准Go项目结构的模板(https://github.com/golang-standards/project-layout)),注意该模板不是Go官方提供的。我们还要注意一些特殊情况,例如,当我们对一个结构体对象调用 encoding/json 标准库对其进行序列化或反序列化时,该结构体对象的字段需要是可导出的(即首字母要大写),否则会忽略该字段。为了帮助用户理解Go项目,我们应该根据它提供的内容命名包,而不是它包含的内容。原创 2024-03-02 10:24:47 · 821 阅读 · 0 评论 -
Go语言必知必会100问题-11 使用选项模式
然后,客户端可以通过下面的代码来实现server的初始化(假设上面的实现放在httplib包中)。首先,客户端创建一个ConfigBuilder对象,用它来设置一个可选字段(像本文的端口)。然后,调用它的Build方法并检查错误信息,如果正确无误,则将配置传给NewServer创建一个server对象。原创 2024-02-29 22:54:30 · 888 阅读 · 0 评论 -
Go语言必知必会100问题-10 小心类型嵌入导致的问题
因此,使用InMem的调用方也可以看到这两个方法. 这种由于内嵌导致的方法提升可能不是我们希望的,在大多数情况下,互斥锁是我们希望封装在结构体内部并且使外部客户端不可见的内容。总结,对于类型嵌入,我们需要知道它不是必须的,这意味着无论什么时候,我们都可以在不使用类型嵌入的情况下解决问题。但是,如果我们没有真正理解类型嵌入的意义,有时可能会导致意想不到的行为。嵌入可以用来提升嵌入类型的字段和方法,像上面的代码,由于Bar包含一个Baz字段,它被提升到Foo中,就好像Foo中定义了一个Baz字段一样。原创 2024-02-29 22:31:24 · 1231 阅读 · 0 评论 -
Go语言必知必会100问题-09 不知道在什么时候该使用泛型
切片不能作为map的key, 编译下面的代码将会报编译错误:invalid map key type []byte. 因此,有必要限制类型参数,而不是接受任何类型的参数,以便键类型满足特定要求。在结构体Node中使用参数类型T来约束Node中存在的数据的类型,字段Val中存储值的类型为T,next节点也带有约束T。在编译时,接收器中的参数类型T将被实例化。T是any类型,所以它是通用的,但它也必须遵守定义的类型参数。有了泛型,现在可以使用类型参数重构上述代码,类型参数是可以与函数和类型一起使用的泛型类型。原创 2024-02-28 20:15:38 · 815 阅读 · 0 评论 -
Go语言必知必会100问题-08 不要过度使用any类型
尽管上述代码可以编译成功,但我们应该花点时间审视一下函数签名,可以发现它接收并返回 any 类型对象, 缺乏表现力,不知道它真正存储的是什么类型的值。将任何类型的值赋值给 any 类型时,会丢失原来的类型信息, 这时需要类型断言才能从变量 i 中获取任何有用的信息。总结,如果确实需要接收或返回任何可能的类型,采用any类型可能会有所帮助。采用any类型,失去了Go作为静态类型语言的一些好处,我们应该避免使用 any 类型,尽可能使函数的签名明确。像下面的代码,any 类型的变量可以保存任何类型的值。原创 2024-02-28 20:13:47 · 591 阅读 · 0 评论 -
Go语言必知必会100问题-07 尽量不要返回接口
当然,也有一些例外情况。最好的例子证明是错误类型,很多函数都会返回一个接口类型的错误(error). 我们还可以使用io包检查标准库中的另外一个异常,像下面的函数返回一个可导出的结构体:io.LimitedReader,但是函数的签名是一个接口:io.Reader, 这不是不符合我们前面的讨论分析吗,为什么要这样实现呢?因为io.Reader是一个提前确定的抽象,它不是由客户端定义的,而是强制存在的,这其实就是前一篇文章中讲的生产者端接口,语言设计者事先知道这种抽象级别在可重用性和可组合性方面有帮助。原创 2024-02-27 22:05:08 · 653 阅读 · 0 评论 -
Go语言必知必会100问题-06 生产者端接口
采用在客户端中定义接口的关键点是客户端可以根据需要定义最准确的抽象(像customersGetter只有一个方法),契合接口隔离原则(SOLID中的I),该原则指出不应强迫任何客户端依赖它不使用的方法。可能认为有很好的理由这样做,我们可能会说,1.这样可以将客户端代码与实际实现分离,2. 在测试的时候,调用方很方便Mock一个假的接口实现进行测试。所提到的,与具有显示实现接口的语言相比,Go中通过隐式实现接口,这会带来一些变化,像其它语言惯用的生产者端接口在Go语言中并不是最佳实践。原创 2024-02-26 22:57:56 · 997 阅读 · 0 评论 -
Go语言必知必会100问题-05 接口污染
对于软件开发人员来说,根据当前情况猜测以后可能有什么需求,来构建完美的抽象,过度设计代码是很常见的,应该避免这样做,因为在大多数情况下,会用不必要的抽象污染当前的代码。这句话想表达的意思是如果没有直接的原因,我们不应该首先在代码中创建抽象,不应该使用接口进行设计,而是等待具体的需求。假设我们需要实现将一个文件内容复制到另一个文件中的函数,我们可以创建一个特定的函数,将两个 *os.File作为输入, 或者可以选择使用io.Reader和io.Writer接口创建一个更通用的函数。答案是它使代码流更加复杂。原创 2024-02-26 22:52:00 · 789 阅读 · 0 评论 -
Go语言必知必会100问题-04 过度使用getter和setter
总结,如果对结构体添加getter和setter方法不会带来任何好处,就不应该添加这些方法,让代码不堪重负。但是,如果发现需要getter和setter,或者在保证向前兼容的同时预见到未来的需求,这种情况下使用getter和setter没有问题。getter和setter是通过在未导出的对象字段上提供导出方法来进行数据封装的方法,在Java语言中使用的比较多,但在Go语言中,没有自动支持它们,所以使用getter和setter访问struct字段不是强制性的,也不是惯用的做法。原创 2024-02-25 11:15:47 · 235 阅读 · 0 评论 -
Go语言必知必会100问题-03 滥用init函数
例如,如果待测函数不依赖数据库连接,即可以直接进行测试,但是在执行测试函数之前init函数先被执行,只有init函数成功执行,才能运行我们的单元测试,这使得编写单元测试变得很复杂。例如在下面的示例中,main包对foo包没有很强的依赖关系,不会使用到foo包中定义的函数,但是需要初始foo包,执行foo包中的init函数,这时可以使用_操作符。在init函数中,使用sql.Open打开一个数据库,并将它赋值给了全局变量,以便在init函数执行后,可以直接使用这个全局变量。初始化包时会执行init函数。原创 2024-02-25 11:13:59 · 1100 阅读 · 0 评论 -
Go语言必知必会100问题-01 小心变量遮蔽
在Go语言中,在代码块中声明的变量可以在内部代码块中重新声明,这种使用方法称为变量遮蔽/隐藏,注意在使用时要非常小心,否则很容易出现常见的错误原创 2023-02-11 13:18:00 · 200 阅读 · 0 评论 -
Go语言中常见100问题-#48 panic
对于Go语言新手来说,在使用error的时候存在一些疑惑。在Go语言中,error通常作为方法或函数的最后一个返回参数。有人可能想采用Java或Python语言中的panic和recover机制来处理异常。Go中也是有异常捕获recover机制的,现在来我们来看在什么场景下使用panic和recover.panic会终止代码执行逻辑panic语句会终止代码执行...原创 2022-06-06 08:21:31 · 897 阅读 · 0 评论 -
说说channel哪些事-下篇
在channel-上篇中,小编主要从channel是什么,为什么需要channel,channel基本的使用方法以及channel实现原理这个四个方面介绍了channel.本篇,小编将从实际的应用场景出发,介绍如何运用chnanel解决这些问题。channel解决的主要是并发问题,学习下面的场景,总结提炼用法,可以帮助我们更好的编写并发程序。for+select多路复用模式for+select多路复用模式非常常见,在实际的工作中也使用的非常频繁,其基本代码模式如下:for { select {原创 2021-06-03 07:51:54 · 549 阅读 · 0 评论 -
说说channel哪些事-上篇
channel是什么channel中文翻译为通道,它是Go语言内置的数据类型,使用channel不需要导入任何包,像int/float一样直接使用。它主要用于goroutine之间的消息传递和事件通知。在Go语言中流传着一句话,就是说不要通过共享内存来通信,而是应该通过通信来共享内存。Don’t communicate by sharing memory, share memory by communicating.上面这句话也包含了通信的两种方式:1是通过共享内存 2是通过通信。channe原创 2021-05-27 07:47:02 · 638 阅读 · 0 评论 -
深入解析Golang之Context
context是什么context翻译成中文就是上下文,在软件开发环境中,是指接口之间或函数调用之间,除了传递业务参数之外的额外信息,像在微服务环境中,传递追踪信息traceID, 请求接收和返回时间,以及登录操作用户的身份等等。本文说的context是指golang标准库中的context包。Go标准库中的context包,提供了goroutine之间的传递信息的机制,信号同步,除此之外还有超时(timeout)和取消(cancel)机制。概括起来,Context可以控制子goroutine的运行,原创 2021-05-22 20:32:48 · 4717 阅读 · 4 评论 -
反射
什么是反射反射?光的反射吗?在物理学中有反射这个概念,表示光在分界面上改变传播方向又返回原来物质中的现象。本文讲述的是反射是在计算机领域的概念,在计算机科学中,反射编程(reflective programming)定义如下,这是来做维基百科的描述。In computer science, reflective programming or reflection is the ability of a process to examine, introspect, and modify its own原创 2021-05-21 22:41:42 · 444 阅读 · 0 评论