当函数即将返回错误时,进行资源清理。

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

go - Cleanup resources only when the function is about to return an error

问题

假设我有一个函数,首先创建一个目录,然后执行一些其他操作,代码如下:

{
    err := os.Mkdir(path, os.ModePerm)
    ...

    err = doSomething()
    if err != nil {
        return nil, err
    }

    err = doSomethingElse()
    if err != nil {
        return nil, err
    }

    return path, nil
}

现在,我希望在发生错误的情况下,函数能够删除它创建的目录。有什么比较简洁的方法可以实现这个需求?

一种方法是在每个 if 分支中调用 os.RemoveAll,但这不是一个很好的解决方案。另一种方法是使用 defer 语句,但这样也会在没有错误的情况下执行。

英文:

Suppose I have a function that starts by creating a directory, and then doing some more stuff, like this:

{
    err := os.Mkdir(path, os.ModePerm)
    ...

    err = doSomething()
    if err != nil {
        return nil, err
    }

    err = doSomethingElse()
    if err != nil {
        return nil, err
    }

    return path, nil
}

Now, I want the function to delete the directory it created in all of those cases where an error occured. What is the cleanest way to do this?

One way would be to call os.RemoveAll in every if branch, but that's not a very nice solution. Another way would be to use a defer statement, but that would also get executed in the case where there was no error.

答案1

得分: 3

是的,延迟函数始终会被执行,但是否删除目录完全取决于你。

使用延迟函数并检查错误。如果没有错误,则不要删除目录。为了使其工作,使用命名返回参数,例如:

func foo() (result resultType, err error) {
    path := "some folder"

    defer func() {
        if err != nil { // 这是结果中的 err
            if err2 := os.RemoveAll(path); err2 != nil {
                // 处理 err2
            }
        }
    }()

    err := os.Mkdir(path, os.ModePerm)
    
    ...
}

请注意,如果有显式的 return 语句,例如:

return path, errors.New("bar")

上述 return 语句首先将值分配给 resulterr,因此在延迟函数中可以获取/查看这些值。

参考链接:https://stackoverflow.com/questions/33167282/how-to-return-a-value-in-a-go-function-that-panics/33167433#33167433

英文:

Yes, a deferred function will always be executed, but whether it deletes the directory depends entirely on you.

Use a deferred function, and check the error. If there was no error, do not delete the directory. For this to work, use named result parameters, e.g.:

func foo() (result resultType, err error) {
	path := "some folder"

	defer func() {
		if err != nil { // This is the result err
			if err2 := os.RemoveAll(path); err2 != nil {
				// handle err2
			}
		}
	}()

	err := os.Mkdir(path, os.ModePerm)
	
	...
}

Note that if there is an explicit return stament like:

return path, errors.New("bar")

The above return statement first assigns the values to result and err, so in deferred functions you can get / see those values.

See related: https://stackoverflow.com/questions/33167282/how-to-return-a-value-in-a-go-function-that-panics/33167433#33167433

huangapple
  • 本文由 发表于 2023年2月4日 19:56:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75344924.html
匿名

发表评论

匿名网友

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

确定