在 golang 中处理逻辑错误与编程错误的惯用方法
Idiomatic way to handle logic error vs programming error in golang
我一直在使用 golang 来自动化一些部署过程,我不得不使用 exec
包来调用一些 bash 脚本。
我用过exec.Command("/home/rodrigo/my-deploy.sh").CombinedOutput()
并且看到了他的实现
func (c *Cmd) CombinedOutput() ([]byte, error) {
if c.Stdout != nil {
return nil, errors.New("exec: Stdout already set")
}
if c.Stderr != nil {
return nil, errors.New("exec: Stderr already set")
}
var b bytes.Buffer
c.Stdout = &b
c.Stderr = &b
err := c.Run()
return b.Bytes(), err
}
我意识到在使用 CombinedOutput()
时不能分配 c.Stdout
,我认为这没问题,但通知 api 调用者的方式不正确。
CombinedOutput()
return 当你以错误的方式使用它时会出错,所以如果你打算使用 CombinedOutput()
那么你不应该分配 c.Stderr
或 c.Stdout
之前,如果你这样做,那么你将收到一个错误。
但是这个错误不是因为你的脚本抛出错误,而是因为你使用的 api 错误,在那种情况下我相信你应该得到一个 panic
因为一个坏的 api 用法不应该被处理(我认为)。
我来自 Java 世界,当您以错误的方式使用某些方法时,您会收到一个 RuntimeException
,例如。
public void run(Job job) throws NotCompletedJob {
if (job.getId() != null) {
throw new IllegalArgumentException("This job should not have id");
}
job.setId(calculateId());
job.run();
}
有了这个签名,我可以知道我用一个有 id 的作业调用 run(obj);
是错误的,事实上我可以区分我的脚本是否有错误或者我正在使用 api 方式不对。
NotCompletedJob
是检查异常所以我必须处理它但 IllegalArgumentException
不是所以我可以随时得到它。捕获 IllegalArgumentException
或任何其他 RuntimeException
并不总是被认为是一个好的做法,因为它们表明从程序员的角度来看你有一个错误,并且它不是像 NotCompletedJob
这样的预期错误。
话虽如此,我如何区分编程错误(例如错误的 api 用法)和当前 CombinedOutput()
实现的预期错误(脚本未正常完成)?
为了澄清我的担忧,我并不是说 CombinedOuput 的当前实现是错误的,但我不明白调用者如何区分是正在执行的命令错误还是由他的错误 api 用法。
我认为最好的方法是在调用者以错误的方式使用 api 时恐慌,就像调用者将 nil 引用传递给期望非无参考(事实上这是当前的行为)。
I come from Java World and when you are using some method in the wrong
way then you receive an RuntimeException.
您现在身处围棋世界。因此,该论点是无效的。放弃Java.
The Go Programming Language Specification
Two built-in functions, panic and recover, assist in reporting and
handling run-time panics and program-defined error conditions.
func panic(interface{})
func recover() interface{}
While executing a function F, an explicit call to panic or a run-time
panic terminates the execution of F. Any functions deferred by F are
then executed as usual. Next, any deferred functions run by F's caller
are run, and so on up to any deferred by the top-level function in the
executing goroutine. At that point, the program is terminated and the
error condition is reported, including the value of the argument to
panic. This termination sequence is called panicking.
The Go Blog
The convention in the Go libraries is that even when a package uses
panic internally, its external API still presents explicit error
return values.
This page collects common comments made during reviews of Go code, so
that a single detailed explanation can be referred to by shorthands.
This is a laundry list of common mistakes, not a style guide.
See https://golang.org/doc/effective_go.html#errors. Don't use panic
for normal error handling. Use error and multiple return values.
The usual way to report an error to a caller is to return an error as
an extra return value.
您的 Go 服务器程序正在同时处理 100,000 个客户端。如果发生错误,报告并处理;始终检查错误。不要用 panic
让所有 100,000 个客户端崩溃。 Go包不应该panic
.
阅读 Go 文档和 Go 标准库代码。
我一直在使用 golang 来自动化一些部署过程,我不得不使用 exec
包来调用一些 bash 脚本。
我用过exec.Command("/home/rodrigo/my-deploy.sh").CombinedOutput()
并且看到了他的实现
func (c *Cmd) CombinedOutput() ([]byte, error) {
if c.Stdout != nil {
return nil, errors.New("exec: Stdout already set")
}
if c.Stderr != nil {
return nil, errors.New("exec: Stderr already set")
}
var b bytes.Buffer
c.Stdout = &b
c.Stderr = &b
err := c.Run()
return b.Bytes(), err
}
我意识到在使用 CombinedOutput()
时不能分配 c.Stdout
,我认为这没问题,但通知 api 调用者的方式不正确。
CombinedOutput()
return 当你以错误的方式使用它时会出错,所以如果你打算使用 CombinedOutput()
那么你不应该分配 c.Stderr
或 c.Stdout
之前,如果你这样做,那么你将收到一个错误。
但是这个错误不是因为你的脚本抛出错误,而是因为你使用的 api 错误,在那种情况下我相信你应该得到一个 panic
因为一个坏的 api 用法不应该被处理(我认为)。
我来自 Java 世界,当您以错误的方式使用某些方法时,您会收到一个 RuntimeException
,例如。
public void run(Job job) throws NotCompletedJob {
if (job.getId() != null) {
throw new IllegalArgumentException("This job should not have id");
}
job.setId(calculateId());
job.run();
}
有了这个签名,我可以知道我用一个有 id 的作业调用 run(obj);
是错误的,事实上我可以区分我的脚本是否有错误或者我正在使用 api 方式不对。
NotCompletedJob
是检查异常所以我必须处理它但 IllegalArgumentException
不是所以我可以随时得到它。捕获 IllegalArgumentException
或任何其他 RuntimeException
并不总是被认为是一个好的做法,因为它们表明从程序员的角度来看你有一个错误,并且它不是像 NotCompletedJob
这样的预期错误。
话虽如此,我如何区分编程错误(例如错误的 api 用法)和当前 CombinedOutput()
实现的预期错误(脚本未正常完成)?
为了澄清我的担忧,我并不是说 CombinedOuput 的当前实现是错误的,但我不明白调用者如何区分是正在执行的命令错误还是由他的错误 api 用法。
我认为最好的方法是在调用者以错误的方式使用 api 时恐慌,就像调用者将 nil 引用传递给期望非无参考(事实上这是当前的行为)。
I come from Java World and when you are using some method in the wrong way then you receive an RuntimeException.
您现在身处围棋世界。因此,该论点是无效的。放弃Java.
The Go Programming Language Specification
Two built-in functions, panic and recover, assist in reporting and handling run-time panics and program-defined error conditions.
func panic(interface{}) func recover() interface{}
While executing a function F, an explicit call to panic or a run-time panic terminates the execution of F. Any functions deferred by F are then executed as usual. Next, any deferred functions run by F's caller are run, and so on up to any deferred by the top-level function in the executing goroutine. At that point, the program is terminated and the error condition is reported, including the value of the argument to panic. This termination sequence is called panicking.
The Go Blog
The convention in the Go libraries is that even when a package uses panic internally, its external API still presents explicit error return values.
This page collects common comments made during reviews of Go code, so that a single detailed explanation can be referred to by shorthands. This is a laundry list of common mistakes, not a style guide.
See https://golang.org/doc/effective_go.html#errors. Don't use panic for normal error handling. Use error and multiple return values.
The usual way to report an error to a caller is to return an error as an extra return value.
您的 Go 服务器程序正在同时处理 100,000 个客户端。如果发生错误,报告并处理;始终检查错误。不要用 panic
让所有 100,000 个客户端崩溃。 Go包不应该panic
.
阅读 Go 文档和 Go 标准库代码。