【发布时间】:2018-11-18 15:22:40
【问题描述】:
我一直在使用 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() 在你以不好的方式使用它时会返回一个错误,所以如果你要使用CombinedOutput() 那么你不应该分配c.Stderr 或c.Stdout 之前,如果你这样做,那么你将收到错误。
但是这个错误不是因为你的脚本抛出错误,而是因为你使用了错误的api,在这种情况下我相信你应该得到一个panic,因为不应该处理糟糕的api使用(我认为) .
我来自 Java World,例如,当您以错误的方式使用某些方法时,您会收到 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 的 Job 调用 run(obj); 是错误的,事实上我可以区分我的脚本是否有错误,或者我以错误的方式使用 api。
NotCompletedJob 是一个检查异常,所以我必须处理它,但IllegalArgumentException 不是,所以我可以随时得到它。捕获IllegalArgumentException 或任何其他RuntimeException 并不总是被认为是一种好的做法,因为从程序员的角度来看,它们表明您有一个错误,而这不是像NotCompletedJob 这样的预期错误。
话虽如此,在当前的CombinedOutput() 实现中,如何区分编程错误(例如错误的 api 用法)和预期错误(脚本未正常完成)?
为了澄清我的担忧,我并不是说当前的 CombinedOuput 实现是错误的,但我不明白调用者如何区分这是正在执行的命令的错误还是由他的错误引起的错误api使用。
我相信最好的方法是在调用者以错误的方式使用 api 时惊慌失措,就像调用者将 nil 引用传递给期望非 nil 引用的函数时一样(实际上这是当前行为)。
【问题讨论】:
-
也许应该是
panic,但这是一个有争议的问题,因为在 go1 中无法更改 API。 -
@JimB 没错,但我相信这是否可以改变并不重要,但它一定是恐慌或错误。
-
因为函数在使用不正确时总是会返回错误,并且错误文本对问题的描述足以让程序员确定这是一个逻辑错误,因此无需以编程方式将逻辑错误与其他错误区分开来在这种情况下。
-
@rvillablanca 也许你的 Java 代码可以在 Golang 中转换to this(是的,据我所知,这是一种常见的模式)
-
询问“CombinedOutput() 的实现是否是最好的方法?”在这里没有用,因为它不是我们要改变的。 API 已设置,因此您可以通过测试来验证您是否正确使用它,或者通过匹配错误字符串来使用它。
标签: go error-handling idioms