惯用语 Go Happy Path

Idiomatic Go Happy Path

假设我们有一个函数 return 有一些值和一个错误。处理错误和值声明的首选方式是什么?

func example_a(data interface{}) (interface{}, error) {
    var err error
    var bytes []byte
    if bytes, err = json.Marshal(data); err != nil {
        return nil, err
    }
    // ... 
    return use(bytes), nil
}

func example_b(data interface{}) (interface{}, error) {
    if bytes, err := json.Marshal(data); err != nil {
        return nil, err
    } else {
        // ... 
        return use(bytes), nil
    }
}

func example_c(data interface{}) (result interface{}, err error) {
    var bytes []byte
    if bytes, err = json.Marshal(data); err != nil {
        return
    }
    // ... 
    return use(bytes), nil
}

func example_d(data interface{}) (interface{}, error) {
    bytes, err := json.Marshal(data)
    if err != nil {
        return nil, err
    }
    // ... 
    return use(bytes), nil
}

func example_dream(data interface{}) (interface{}, error) {
    if bytes, err ≡ json.Marshal(data); err != nil {
        return nil, err
    }
    // ... 
    return use(bytes), nil
}

示例 A 很清楚,但它增加了 2 行。此外,我发现不清楚为什么在这种特殊情况下我们应该使用 var,同时 := 并不总是合适的。然后你想在某处重用 err 声明,我不喜欢拆分声明和赋值。

示例 B 使用了 if-declare-test 语言特性,我认为这是值得鼓励的,但同时你被迫嵌套函数继续,违反了 happy-路径原则,这也是被鼓励的。

示例 C 使用命名参数 return 特性,它介于 A 和 B 之间。这里最大的问题是,如果您的代码库使用样式 B和C,那么很容易弄错:==,会导致各种问题。

示例 D(根据建议添加)对我来说有与 C 相同的使用问题,因为我不可避免地 运行 进入以下内容:

func example_d(a, b interface{}) (interface{}, error) {
    bytes, err := json.Marshal(a)
    if err != nil {
        return nil, err
    }

    bytes, err := json.Marshal(b) //Compilation ERROR
    if err != nil {
        return nil, err
    }

    // ... 
    return use(bytes), nil
}

因此,根据之前的声明,我必须修改我的代码以使用 :==,这使得查看和重构变得更加困难。

Example Dream 是我直觉上对 GO 的期望——没有嵌套,快速退出,没有太多冗长和变量重用。显然它不能编译。

通常 use() 被内联并多次重复该模式,使嵌套或拆分声明问题更加复杂。

那么,处理此类多个 return 和声明的最惯用的方法是什么?有没有我遗漏的模式?

如果你查看大量 Go 代码,你会发现以下是常见的情况:

func example(data interface{}) (interface{}, error) {
    bytes, err := json.Marshal(data)
    if err != nil {
        return nil, err
    }
    // ... 
    return use(bytes), nil
}

declare and test if 构造在它的位置上很好,但在这里通常不合适。