Golang Go语言中一种不作不会死的方式
不捕获 error
典型的像如下代码:
func getBar()(*bar, err){
//some errors
if err := hasError(); err != nil{
return nil, err
}
//do sth
return new(bar), nil
}
func foo(){
b, _ := getBar()
b.DoSth() //panic
}
以下典型的 golang 代码看起来很烦,而且直接影响代码风格美观程度。
func getBar()(*bar, err){
//do sth
return 0, nil
}
func foo()error{
if b1, err := getBar(); err != nil{
return err
}
if b2, err := getBar(); err != nil{
return err
}
return nil
}
我在很多项目里看到新手或者从其他语言转过来的同学,喜欢写 if p, _ := getBar()
这样的代码,然后继续处理接下来的流程。这样做的问题在于你直接忽略掉了你所调用代码产生的错误,你内心默认的代码运行方式是:“我的代码一定会以正确的方式运行。”
在很多其他的语言里会有 try catch 这样的机制,可以让你在函数调用的外部直接捕获异常。当随之带来的问题是 try catch 是跨函数跨模块和函数的,容易出现抛出的异常被并不适合这个模块的代码模块去处理。
go 语言这个错误处理方式虽然丑陋,但简单有效。它这样做简单的让你把 error 直接丢给上一层,上一层可以决定这个错误是继续传递还是中止处理。当我把写 go 关于错误处理的思维方式转变成:不放过任何一个错误后,写代码的心智负担将得极低。我只需要关心当前的函数输入输出数据是否合法,以及调用其他函数时出错后选择继续还是中止。而且 go 语言这种小粒度的 error 处理方式几乎不用 care 错误的类型,遇到不合法 /异常 /错误 /非正常流程后只需要 error 继续 /中止一把梭即可。
不信你可以看看下面是如何用简单的错误处理是如何改掉 HTTP 200 一把梭的毛病。
func Query(w http.ResponseWriter, r *http.Request) {
var data RequestData
err := json.NewDecoder(r.Body).Decode(&data)
if err != nil{
w.WriteHeader( http.StatusBadRequest)
return
}
if data.Name == "not existed"{
w.WriteHeader( http.StatusNotFound)
return
}
w.WriteHeader( http.StatusOK)
return
}
某些 golang 的 web framework 会调用 recover 方法,以防止 HTTP server 崩溃。不得不说这是它提供的一种“助纣为虐”的方式让你去忽略掉某些致命的错误。这完全没必要,守护进程比 recover 要靠谱得多(还能自动获得重启大法的加成:) )。我个人认为在代码里面尽量不要调用任何 recover 的代码,尽量在代码部署到生产环境前测试发现所有可能的 panic 错误并修复掉。如果代码发生 panic 问题,肯定是有什么地方你没有想到或没设计好,你需要做的是修改代码而不是掩盖错误。
捕获所有错误你唯一需要付出的代价就是:多敲几个字。而付出的这点代价你将获得:底层成本的设计负担,无脑的心智负担,健壮的代码,严格的输入输出限定。
Golang Go语言中一种不作不会死的方式
更多关于Golang Go语言中一种不作不会死的方式的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
用不用 recover 还是得看场景,对于开发来说,当然希望 panic 被我们感知到比较好,但是有些 to B 产品,甲方是会关注你是否有 panic 的,对于这种,我们需要做到既不 panic (不被甲方知道)同时我们又能知道服务出现过问题,总之就是具体事情具体分析。永远不能脱离业务
更多关于Golang Go语言中一种不作不会死的方式的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我是这样安慰自己的:总比 C 返回一个 err code 好吧。。。。
主要还是太丑了,rust 用模式匹配看起来就美观很多
panic 了整个进程就退出了,web framework 的所有其它并发请求都会失败,而如果 recover ,则不会影响其它并发请求。再说发现程序是否有 panic ,不一定要进程退出,panic 打点 metrics 告警也能发现问题
总之就是太丑而且说真的麻烦,错误处理还得看 C#(你甚至都不知道它到底会不会报错)
判断 err != nil 才是恶心的根源
你捕获了又能怎么样呢,你能写出绝对完美的程序?自欺欺人,不如直接忽略掉,在重要的地方捕获 err 或者打日志,只有妥协,才能走的更快
可能说的是 C#异常不像 Java 那样必须 try catch 捕获,不然编译不过? 反正 Java 检查性异常满屏的 try catch ,看起来也十分不雅,我会用 lombok 插件来处理这种情况。
只是在说对 C#的无奈
很多情况下如果写库的人不在注释里面标注要报什么错,我都不知道要不要 try 它
只有真出了问题才知道要 try
java 很多时候套个 aop 就直接抛就行了…统一做处理就可以了
绝大多数觉得 go 语言错误处理不好的都是菜逼. 因为 go 的错误处理跟 c 语言是一样的,而且比 c 语言好.
并且 go 是有 try catch 模式的(不是 recover 那种) 每次看见一群菜鸟喷 err 错误处理就想笑 咋没人喷 c 的错误处理?
在Golang(Go语言)中,确实存在一些编程实践,如果不加以注意,可能会导致代码难以维护、性能低下,甚至引发运行时错误。这些“不作不死”的方式,往往源于对语言特性理解不足或编程习惯不良。以下是一些常见的陷阱及建议:
-
忽略错误处理:Go语言强调显式错误处理。忽略错误(如使用
_
接收错误)可能导致潜在问题被掩盖。建议总是检查并妥善处理错误。 -
过度使用全局变量:全局变量会增加代码间的耦合度,降低模块性。建议使用局部变量、结构体字段或接口来传递数据。
-
不恰当的并发处理:Go的并发模型强大,但滥用
goroutine
和channel
可能导致资源泄漏、死锁等问题。确保正确使用同步机制,如sync.WaitGroup
、sync.Mutex
等。 -
忽视内存管理:虽然Go有垃圾回收机制,但不当的内存使用(如大量分配小对象)仍可能影响性能。使用
pprof
等工具进行性能分析,优化内存使用。 -
不遵循编码规范:一致的编码风格有助于提高代码可读性。遵循Go的官方编码规范,使用
gofmt
等工具格式化代码。
总之,避免“不作不死”的关键在于深入理解Go语言的特性和最佳实践,并养成良好的编程习惯。通过不断学习和实践,可以编写出高效、可维护的Go语言代码。