尽早 `return` 而不是深度嵌套
发布者:admin 发表于:435天前 阅读数:677 评论:0

由于 Go 语言的控制流不使用 exception,因此不需要为 trycatch 块提供顶级结构而深度缩进代码。Go 语言代码不是成功的路径越来越深地嵌套到右边,而是以一种风格编写,其中随着函数的进行,成功路径继续沿着屏幕向下移动。 我的朋友 Mat Ryer 将这种做法称为“视线”编码。[@matryer](https://medium.com//line-of-sight-in-code-186dd7cdea88"target="_blank">[4]

这是通过使用 guard clauses 来实现的; 在进入函数时是具有断言前提条件的条件块。 这是一个来自 bytes 包的例子:

func (b *Buffer) UnreadRune() error {
    if b.lastRead <= opInvalid {
        return errors.New("bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune")
    }
    if b.off >= int(b.lastRead) {
        b.off -= int(b.lastRead)
    }
    b.lastRead = opInvalid
    return nil
}

进入 UnreadRune 后,将检查 b.lastRead 的状态,如果之前的操作不是 ReadRune,则会立即返回错误。 之后,函数的其余部分继续进行 b.lastRead 大于 opInvalid 的断言。

与没有 guard clause 的相同函数进行比较,

func (b *Buffer) UnreadRune() error {
    if b.lastRead > opInvalid {
        if b.off >= int(b.lastRead) {
            b.off -= int(b.lastRead)
        }
        b.lastRead = opInvalid
        return nil
    }
    return errors.New("bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune")
}

最常见的执行成功的情况是嵌套在第一个if条件内,成功的退出条件是 return nil,而且必须通过仔细匹配大括号来发现。 函数的最后一行是返回一个错误,并且被调用者必须追溯到匹配的左括号,以了解何时执行到此点。

对于读者和维护程序员来说,这更容易出错,因此 Go 语言更喜欢使用 guard clauses 并尽早返回错误。