在一系列系统调用中,是否有更简洁的错误处理方式?

huangapple go评论74阅读模式
英文:

Is there a cleaner way of error handling in a series of system calls?

问题

以下函数通过一系列系统调用来扩大映射文件缓冲区:

func (file *File) Ensure(more int) (err error) {
    if file.Append+more <= cap(file.Buf) {
        return
    }

    // 没有足够的空间
    if err = syscall.Munmap(file.Buf); err != nil {
        return
    }
    if _, err = file.Fh.Seek(0, os.SEEK_END); err != nil {
        return
    }
    if _, err = file.Fh.Write(make([]byte, file.Growth)); err != nil {
        return
    }
    if err = file.Fh.Sync(); err != nil {
        return
    }
    if file.Buf, err = syscall.Mmap(int(file.Fh.Fd()), 0, cap(file.Buf)+file.Growth, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED); err != nil {
        return
    }
    return
}

在5行代码中进行了5个系统调用,并且有11行的错误处理代码。有没有更简洁的方法来做到这一点?

英文:

The following function makes a series of system calls to enlarge a mapped file buffer:

func (file *File) Ensure(more int) (err error) {
	if file.Append+more &lt;= cap(file.Buf) {
		return
	}

	// there is not enough room
	if err = syscall.Munmap(file.Buf); err != nil {
		return
	}
	if _, err = file.Fh.Seek(0, os.SEEK_END); err != nil {
		return
	}
	if _, err = file.Fh.Write(make([]byte, file.Growth)); err != nil {
		return
	}
	if err = file.Fh.Sync(); err != nil {
		return
	}
	if file.Buf, err = syscall.Mmap(int(file.Fh.Fd()), 0, cap(file.Buf)+file.Growth, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED); err != nil {
		return
	}
	return
}

5 system calls are made in 5 lines and there are 11 lines of error handling code. Is there a cleaner way to do this?

答案1

得分: 1

这取决于你对“干净”的定义。有些人认为,在处理错误时,与异常相比,错误发生的地方是干净的。请注意,在每个错误路径中,都有一个干净的代码点,除了默认操作(返回错误)之外,还可以采取其他操作。可以尝试恢复(如果适用),可以修复错误并提供更多细节,例如关于哪个调用失败的可读标签。当意识到很容易从绝对多于一个系统调用中获得某种等效的错误(例如 EPERM 或 EINVAL)时,这实际上是一个好主意。

另一个观察是:如果要消除错误检测(if err != nil)和错误处理操作(在这种情况下是return),它应该如何实现(即使这被假设为更干净)?

英文:

It depends on your definition of cleanness. Some people think that handling an error where it occurs, in contrast to exceptions, is clean. Notice how you have in every of the error paths a clean point in code where other than default action (returning the error) can be taken. It can be an attempt to recover (where aplicable), it can ammend the error with more details, for example human readable tag about which of the five calls failed. Which is actually a good idea when one realizes that is easy to get some equivalent of, say EPERM or EINVAL from definitely more than one syscall.

Another observation is: How it is supposed to eliminate (if that would be hypothetically perceived as cleaner) the error detecting (if err != nil) and on-error action (return in this case)?

答案2

得分: 1

在你的例子中,很难看出错误检查模式是一个好的模式。与JVM和类似的语言进行比较,每个调用都会抛出一个异常,而这种模式需要的代码行数要少得多,也不那么麻烦。

然而(这是一个很大的“然而”),在其他情况下,你可能需要对每个错误情况进行不同的处理。按照Go的风格,这很容易。按照异常的风格,这并不容易;相反,需要大量的try-catch块,并且所需的仪式感会被颠倒。

所以我的结论是,我认为Go的模式有点繁琐,但我也认识到有时候这是一件好事,这弥补了繁琐。我在启动代码中经常使用panic,这样我就不需要从本质上无法恢复的事情中进行恢复。

最后观察一下,函数式编程专家(例如Scala中的专家)喜欢所谓的“Either”模式,其中函数返回结果或错误;这与Go的模式实际上是相同的。

英文:

In your example, it is less obvious that the error-checking pattern is a good one. Comparing it with JVM and similar languages, an exception would be thrown by each of these calls and that pattern would require far fewer lines and a lot less fuss.

However (and it's a big 'however'), in other cases you might need to handle each error case differently from the others. In the Go style, this is easy. In the exception style, it's not; instead a lot of try-catch blocks would be needed and the amount of ceremony needed would be inverted.

So my conclusion is that I find the Go pattern a little of chore, but I appreciate there are times that it's a Good Thing and that makes up for the chore. I also find myself using panic a lot in startup code so I don't need any recovery from things that are essentially unrecoverable.

As a final observation, the functional programming pundits (e.g. in Scala) like the so-called Either pattern where a function returns either a result or an error; this is in preference to using exceptions. It's the same pattern as Go's really.

huangapple
  • 本文由 发表于 2013年5月18日 18:13:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/16623091.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定