我今天开始学习Go
有一件事让我发疯,它是err
返回的参数。
我们假设我需要嵌套一些函数。像这样:
return string(json.Marshal(MyData))
或更复杂的例子:
return func1(func2(func3(MyData)))
是否真的有必要写:
tmp1 , _ = func3(MyData)
tmp2 , _ = func2(tmp1)
tmp3 , _ = func1(tmp2)
return tmp3
那很烦人! 有没有办法让代码看起来更干净?
答案 0 :(得分:5)
真正的答案是:不要。
永远不要忽略错误。
严重。错误是有原因的。如果函数返回错误, 它几乎总是意味着在你的程序运行期间,它是可能的, 即使它是100%无错误的,因为该功能失败。如果确实如此, 你通常不想继续前进,好像什么都没发生一样。
如果你完全确定你正在使用某个功能,以确保它永远不会返回一个非零错误(除非你的程序中有错误,并且始终存在is),您可能希望编写一个Must
样式的函数,就像在template
package中一样,它会返回错误值。
错误处理不是噪音。这不是混乱。这不是你想要的东西 摆脱。如果看起来50%的程序是错误的 处理,这是因为50%的程序是,应该是错误处理。
答案 1 :(得分:1)
可以定义一个忽略错误的函数,但是Go缺少泛型使得你不得不在整个地方使用接口{}和类型转换,失去了很多静态保证来自typechecker的过程。这非常难看。不要这样做。
func ignoreError(val interface {}, err error) interface {} {
return val
}
每次调用ignoreError()
时,您都必须对预期的返回类型进行类型转换。
答案 2 :(得分:0)
您经常会看到的一种可能的抽象模式是使用通用错误处理程序。
这并不能防止您必须处理错误值,但可以抽象处理错误而不涉及其余代码。
请注意,将此类抽象视为“非惯用的” Go,“纯”方式是明确地就地处理错误。但是,这种由恐慌驱动的替代方案仍然非常有用,特别是对于快速制作原型脚本的情况,在该脚本中您只想将所有错误转储到控制台或日志文件中。
对于可重用的程序包,我会坚持使用冗长的显式方式,因为其他人希望产生错误的函数实际返回错误值,而不是使用紧急恢复机制。
package main
import (
utils
)
func main() {
defer func() {
utils.Handle(func(err error) {
// Handle errors in a generic way,
// for example using println, or writing to http
})
}()
var result, err := someFragileFunction()
Check(err)
}
package utils
func Check(err error) {
if err != nil {
panic(err)
}
}
func Handle(handler func(err error)) {
if r := recover(); r != nil {
if err, ok := r.(error); ok {
handler(err)
} else {
panic(r)
}
}
}