Go语言开发小技巧&易错点100例(一)

简介: Go语言开发小技巧&易错点100例(一)

全民制作人们大家好,我是练习时长两年半的个人练习生Barry Yan,喜欢唱、跳、Coding、羽毛球,Music!

今天给大家带来的这一档文章呢,主要是总结一下自己Coding过程中遇到的问题以及平时读一些博客的所得,因为做gopher也有了一段时间了,相比Java,有些问题的出现想要利用搜索引擎排查出来可能不是那么的迅速,所以在这里以文章的形式总结出来也方便各位初出茅庐的gopher们能够顺利的解决所遇到的问题,并能够习得一些小技巧。

为什么叫《Go语言开发小技巧&易错点100例》呢,说实话我也不知道能不能写到100例,只能说作为自己的一个小目标吧,先赚它一个亿,哈哈哈,只有目标才能促使自己不断Coding,不断发现和总结问题,相信到最后肯定要多于100个的,今天就先来9个!

先罗列一下吧(技巧类用【技】表示,易错点用【易】表示)

(1)return返回值屏蔽【技】

(2)context继承【易】

(3)禁止main退出【技】

(4)map遍历次序【易】

(5)main函数提前退出【易】

(6)包循环依赖【易】

(7)fallthrough关键字【技】

(8)简式变量声明(i:=1)仅能在函数内部使用【易】

(9)interface断言【易】

正文

1 return返回值屏蔽【技】

返回值屏蔽的概念就是直接return也能返回函数的返回值,但是需要将返回值进行赋值操作,比如我们定义一个函数:func method(parm string) string,返回值为string类型,实现函数时就会要求我们必须要return一个string类型的变量,但是如下的代码示例中直接一个return,并且也能正常执行

func Hello(name string) (str string) {
   str = "Hello World"
   if name != "" {
      return "Hello " + name
   }
   return
}
func main() {
   fmt.Println(Hello(""))
   fmt.Println(Hello("zs"))
}

运行结果:

Hello World
Hello zs

这就是返回值屏蔽的效果,但是要想实现,就必须也要像定义参数一样去定义返回值,如func method(parm string) res string,就可以直接进行return了。

2 context继承【易】

众所周知,在Go开发中context包是一个很常用并且重要的包,

func Handler(ctx context.Context) {
  fmt.Println(ctx.Value("name"))
  fmt.Println(ctx.Deadline())
}
func Controller(ctx context.Context) {
  fmt.Println(ctx.Value("name"))
  fmt.Println(ctx.Deadline())
  ctx = context.WithValue(ctx, "name", "ls")
  ctx, _ = context.WithTimeout(ctx, time.Second*10)
  Handler(ctx)
}
func main() {
  ctx := context.WithValue(context.Background(), "name", "zs")
  ctx, _ = context.WithTimeout(ctx, time.Second*5)
  Controller(ctx)
}

运行结果:

zs
2022-10-15 14:38:46.0456413 +0800 CST m=+5.005663601 true
ls
2022-10-15 14:38:46.0456413 +0800 CST m=+5.005663601 true

context的部分规则如下:

  • WithCancel:基于父级 context,创建一个可以取消的新 context。
  • WithDeadline:基于父级 context,创建一个具有截止时间(Deadline)的新 context。
  • WithTimeout:基于父级 context,创建一个具有超时时间(Timeout)的新 context。
  • Background:创建一个空的 context,一般常用于作为根的父级 context。
  • TODO:创建一个空的 context,一般用于未确定时的声明使用。
  • WithValue:基于某个 context 创建并存储对应的上下文信息。

一般会有父级 context 和子级 context 的区别,我们要保证在程序的行为中上下文对于多个 goroutine 同时使用是安全的。并且存在父子级别关系,父级 context 关闭或超时,可以继而影响到子级 context 的程序。

3 禁止main退出【技】

方式一:

func main() {
   defer func() {for {}}()
   // TODO
}

方式二:

func main() {
   defer func() { select {} }()
   // TODO
}

方式三:

func main() {
   // TODO
   select {}
}

4 map遍历次序【易】

Go语言中map的遍历次序是无序的哈

func main() {
   m := make(map[string]string)
   m["A"] = "a"
   m["B"] = "b"
   m["C"] = "c"
   m["D"] = "d"
   m["E"] = "e"
   for i := range m {
      fmt.Println(i)
   }
}

运行结果:

C
D
E
A
B

5 main函数提前退出【易】

你是否遇见过这种情况:

func main() {
   go func() {
      fmt.Println("Hello goruntine")
   }()
   fmt.Println("Hello main")
}

运行结果:

第一次运行:
Hello main
第n次运行:
Hello main
Hello goruntine
第n+1次运行:
Hello goruntine
Hello main

为什么会导致这样的结果呢?

答案就是多线程,并且他们的线程并不是互斥的。

解决方式

不专业的方式

func main() {
   go func() {
      fmt.Println("Hello goruntine")
   }()
   fmt.Println("Hello main")
   time.Sleep(time.Second * 5)
}

专业的方式

func main() {
   group := sync.WaitGroup{}
   group.Add(1)
   go func() {
      defer group.Done()
      fmt.Println("Hello goruntine")
   }()
   fmt.Println("Hello main")
   group.Wait()
}

6 包循环依赖错误【易】

先说明下场景:

我们在dao层的文件中定义结构体和其相关的dao层方法,但是在调用方法时(如插入数据的方法)会使用utils包中的工具方法对参数进行检查,而utils中的工具方法需要引用dao层的结构体才能够检查,因此出现了dao依赖utils包,utils包依赖dao包的情况,就导致了循环依赖的异常。

dao包文件:

package dao
import (
   "fmt"
   "other/article/utils"
)
type User struct {
   Name string
}
func InsertUser() {
   utils.CheckUser()
   fmt.Println("InsertUser")
}

utils包文件:

package utils
import (
   "fmt"
   "other/article/dao"
)
func CheckUser() {
   user := dao.User{Name: "zs"}
   fmt.Println("CheckUser", user)
}

main文件:

package main
import (
  "other/article/dao"
)
func main() {
   dao.InsertUser()
}

运行结果:

package command-line-arguments
  imports other/article/dao
  imports other/article/utils
  imports other/article/dao: import cycle not allowed

解决方式

将dao层的结构体移到一个新包中,并且dao和utils都引用这个新包。

这个错误也告诉我们一个道理,就是代码要注意划分层次,低内聚,才能更好的增加代码的可读性。

7 fallthrough关键字【技】

Go里面switch默认相当于每个case最后带有break,匹配成功后不会自动向下执行其他case,而是跳出整个switch, 但是可以使用fallthrough强制执行后面的case代码。

func main() {
   i := 10
   switch i {
   case 1:
      fmt.Println(1)
   case 5:
      fmt.Println(5)
      fallthrough
   case 10:
      fmt.Println(10)
      fallthrough
   case 20:
      fmt.Println(20)
   default:
      fmt.Println("default")
   }
}

运行结果:

10
20

8 简式变量声明仅能在函数内部使用【易】

什么是简式变量声明呢,我们知道Go声明变量有两种方式

// 第一种
var i int
i = 10
// 第二种 (简式变量声明)
i := 10

而第二种变量声明就不可以在方法外使用

9 interface断言【易】

func main() {
   var value interface{}
   value = "hello"
   str := value.(string)
   fmt.Println(str)
   value = 100
   i := value.(int32)
   fmt.Println(i)
}

运行结果:

hello
panic: interface conversion: interface {} is int, not int32
......

解决方式

在断言之前先做一个类型判断

func main() {
   var value interface{}
   value = 100
   switch value.(type) {
   case int32:
      fmt.Println(value.(int32))
   case string:
      fmt.Println(value.(string))
   case int:
      fmt.Println(value.(int))
   }
}

当然GitHub有更好的方式可以将interface类型转化成我们需要的类型,比如cast插件。

参考:

https://chai2010.cn/advanced-go-programming-book/appendix/appendix-a-trap.html

https://errorsingo.com/

https://www.kancloud.cn/gopher_go/go/848998

https://blog.csdn.net/Guzarish/article/details/119627758

相关文章
|
4天前
|
监控 Linux PHP
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
52 20
|
3天前
|
存储 监控 算法
探秘员工泄密行为防线:基于Go语言的布隆过滤器算法解析
在信息爆炸时代,员工泄密行为对企业构成重大威胁。本文聚焦布隆过滤器(Bloom Filter)这一高效数据结构,结合Go语言实现算法,帮助企业识别和预防泄密风险。通过构建正常操作“指纹库”,实时监测员工操作,快速筛查可疑行为。示例代码展示了如何利用布隆过滤器检测异常操作,并提出优化建议,如调整参数、结合日志分析系统等,全方位筑牢企业信息安全防线,守护核心竞争力。
|
10天前
|
Go C语言
Go语言入门:分支结构
本文介绍了Go语言中的条件语句,包括`if...else`、`if...else if`和`switch`结构,并通过多个练习详细解释了它们的用法。`if...else`用于简单的条件判断;`if...else if`处理多条件分支;`switch`则适用于基于不同值的选择逻辑。特别地,文章还介绍了`fallthrough`关键字,用于优化重复代码。通过实例如判断年龄、奇偶数、公交乘车及成绩等级等,帮助读者更好地理解和应用这些结构。
34 14
|
25天前
|
存储 监控 算法
内网监控系统之 Go 语言布隆过滤器算法深度剖析
在数字化时代,内网监控系统对企业和组织的信息安全至关重要。布隆过滤器(Bloom Filter)作为一种高效的数据结构,能够快速判断元素是否存在于集合中,适用于内网监控中的恶意IP和违规域名筛选。本文介绍其原理、优势及Go语言实现,提升系统性能与响应速度,保障信息安全。
28 5
|
1月前
|
算法 安全 Go
Go语言中的加密和解密是如何实现的?
Go语言通过标准库中的`crypto`包提供丰富的加密和解密功能,包括对称加密(如AES)、非对称加密(如RSA、ECDSA)及散列函数(如SHA256)。`encoding/base64`包则用于Base64编码与解码。开发者可根据需求选择合适的算法和密钥,使用这些包进行加密操作。示例代码展示了如何使用`crypto/aes`包实现对称加密。加密和解密操作涉及敏感数据处理,需格外注意安全性。
46 14
|
1月前
|
存储 安全 Go
Go语言中的map数据结构是如何实现的?
Go 语言中的 `map` 是基于哈希表实现的键值对数据结构,支持快速查找、插入和删除操作。其原理涉及哈希函数、桶(Bucket)、动态扩容和哈希冲突处理等关键机制,平均时间复杂度为 O(1)。为了确保线程安全,Go 提供了 `sync.Map` 类型,通过分段锁实现并发访问的安全性。示例代码展示了如何使用自定义结构体和切片模拟 `map` 功能,以及如何使用 `sync.Map` 进行线程安全的操作。
|
10天前
|
监控 关系型数据库 MySQL
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
19 0
|
2月前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
95 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
2月前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
48 7
|
2月前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。