与Rust般的结果类型进行简明错误处理
#编程 #go #rust #softwareengineering

我最近开始学习Rust,我真的很喜欢Result Enum和?运营商的实用程序和简洁。因此,我试图看看我能在旅途中实现类似的东西有多近。此外,当某人说“哦,错误处理如此冗长”时,我可以指出这一点。

如果您不熟悉Rust,则koude0类型是可以容纳Ok有效值或错误的枚举。这很整洁,但真正的实用程序来自?操作员。当?Result上调用?运算符时,如果Result中存在错误,并且只需从父函数返回Result,则将停止执行代码。基本上,Rust仅用一个字符代替了以下众所周知的Go错误处理样板!

if err != nil {
    return nil, err
}

如果Result中没有错误,则操作员将拆开Ok值并返回。

Rust和Go是完全不同的,因此从GO中实现相同的Result Enum和?操作员并不像移植或翻译代码那样简单。这是我遇到的一些挑战,以及我如何解决它们。

枚举

我认为Go的枚举可能是限制的,并且不像Rust的表现力是很热门的。因此,而不是在Result类型的go中使用枚举,而不是使用generics和struct。

type Result[T any] struct {
    Ok  T
    Err error
}

问号操作员

这是一个更大的问题。据我所知,GO的功能与此相似。打破“自愿”函数流动流的唯一方法是惊慌。因此,我决定可以在Result结构上添加一种方法,如果存在错误,该方法会感到恐慌。但这还不是全部,我仍然需要某种方法来恢复此恐慌,并让错误“弹起”呼叫堆栈。实现此目的的方法是将命名的Result从父函数返回,将指针传递给该名称的Result到递延功能,该功能将从恐慌中恢复,并将错误放在该指针中。我们称此延期函数EscapeHatch。这就是外观:

func EscapeHatch[T any](res *Result[T]) {
    if r := recover(); r != nil {
        err, ok := r.(ehError)
        if !ok {
            // Panicking again because the recovered panic is not an ehError
            panic(r)
        }
        *res = Result[T]{Err: err.error}
    }
}

这里还有一件事。也就是说,我们通过?操作员引起的任何恐慌都包裹在一个简单的结构中,以便我们仅恢复这些恐慌,并再次为所有其他结构恢复。最后,因为?不是Go中的方法的有效名称,而是使用Eh。这对于EscapeHatch来说是缩写,也是加拿大人在句子结尾处添加的东西,以使其成为问题。例如:“我们的天气很愉快,是吗?”。因此,我认为这是?操作员的适当替代。

演示时间!

将所有内容整合在一起,我可以像这样转换代码:

func example(aFile string) ([]byte, error) {
    f, err := os.Open(aFile)
    if err != nil {
        return nil, err
    }
    buff := make([]byte, 5)
    _, err := f.Read(b1)
    if err != nil {
        return nil, err
    }
    return buff, nil

进入这个:

func example(aFile string) (res eh.Result[[]byte]) {
    defer eh.EscapeHatch(&res)  // must have pointer to the named output Result
    buff := make([]byte, 5)
    file := eh.NewResult(os.Open(aFile)).Eh()
    _ = eh.NewResult(file.Read(buff)).Eh()
    return eh.Result[[]byte]{Ok: buff}

这不是真的骇人听闻吗?

最初,我对这个想法感到更糟,尤其是在这种方式上可能“滥用”恐慌。但是后来我发现,即使是标准GO库中的json package也会使用恐慌,包裹错误并在递归编码接口时恢复错误以停止执行。因此,如果这是一个反模式,那么至少我可以说标准库也在这样做。

无耻库插头

如果您很好奇,我将所有代码和一些实用程序功能组合在一个小包装here中。尝试一下,让我知道您的想法。