1

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

func (file *File) Ensure(more int) (err error) {
    if file.Append+more <= 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 行中进行了 5 个系统调用,并且有11行错误处理代码。有没有更清洁的方法来做到这一点?

4

2 回答 2

1

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)?

于 2013-05-18T10:26:06.467 回答
1

在您的示例中,错误检查模式是一个好的模式不太明显。将其与 JVM 和类似语言进行比较,这些调用中的每一个都会引发异常,并且该模式将需要更少的行和更少的麻烦。

但是(这是一个很大的“但是”),在其他情况下,您可能需要以不同的方式处理每个错误情况。在 Go 风格中,这很容易。在异常风格中,它不是;取而代之的是,需要大量的 try-catch 块,并且所需的仪式量将被倒置。

所以我的结论是,我发现 Go 模式有点繁琐,但我很欣赏有时它是一件好事并且弥补了繁琐的工作。我还发现自己panic在启动代码中使用了很多,所以我不需要从本质上无法恢复的东西中恢复。

作为最后的观察,函数式编程专家(例如在 Scala 中)喜欢所谓的Either模式,即函数返回结果或错误。这优先于使用异常。这与 Go 的模式相同。

于 2013-05-18T17:42:45.680 回答