ruby-on-rails - 在 Ruby 中开始、拯救和确保?

标签 ruby-on-rails ruby exception exception-handling error-handling

我最近开始使用 Ruby 编程,并且正在研究异常处理。

我想知道 ensure 是否等同于 C# 中的 finally?我应该:

file = File.open("myFile.txt", "w")

begin
  file << "#{content} \n"
rescue
  #handle the error here
ensure
  file.close unless file.nil?
end

或者我应该这样做吗?

#store the file
file = File.open("myFile.txt", "w")

begin
  file << "#{content} \n"
  file.close
rescue
  #handle the error here
ensure
  file.close unless file.nil?
end

是否确保无论如何都会被调用,即使没有引发异常?

最佳答案

是的,ensure 确保代码始终被评估。这就是它被称为 ensure 的原因。所以,它相当于Java和C#的finally

begin/rescue/else/ensure/end的一般流程> 看起来像这样:

begin
  # something which might raise an exception
rescue SomeExceptionClass => some_variable
  # code that deals with some exception
rescue SomeOtherException => some_other_variable
  # code that deals with some other exception
else
  # code that runs only if *no* exception was raised
ensure
  # ensure that this code always runs, no matter what
  # does not change the final value of the block
end

您可以省略rescueensureelse。您也可以省略变量,在这种情况下您将无法在异常处理代码中检查异常。 (好吧,您始终可以使用全局异常变量来访问最后引发的异常,但这有点老套。)您可以省略异常类,在这种情况下,所有继承自 StandardError< 的异常 将被捕获。 (请注意,这并不意味着捕获了所有 异常,因为有一些异常是Exception 而不是StandardError 的实例。大多数非常危及程序完整性的严重异常,例如 SystemStackErrorNoMemoryErrorSecurityErrorNotImplementedError LoadErrorSyntaxErrorScriptErrorInterruptSignalExceptionSystemExit .)

一些 block 形成隐式异常 block 。例如,方法定义隐式也是异常 block ,所以不用写

def foo
  begin
    # ...
  rescue
    # ...
  end
end

你只写

def foo
  # ...
rescue
  # ...
end

def foo
  # ...
ensure
  # ...
end

这同样适用于 class 定义和 module 定义。

但是,在您询问的特定情况下,实际上有一个更好的成语。通常,当您使用某些需要在最后清理的资源时,您可以通过将一个 block 传递给一个为您完成所有清理工作的方法来做到这一点。它类似于 C# 中的 using block ,只是 Ruby 实际上足够强大,您不必等待 Microsoft 的大祭司下山并慷慨地为您更改他们的编译器.在 Ruby 中,您可以自己实现它:

# This is what you want to do:
File.open('myFile.txt', 'w') do |file|
  file.puts content
end

# And this is how you might implement it:
def File.open(filename, mode='r', perm=nil, opt=nil)
  yield filehandle = new(filename, mode, perm, opt)
ensure
  filehandle&.close
end

您知道什么:这已经在核心库中作为 File.open 可用。但它是一种通用模式,您也可以在自己的代码中使用,以实现任何类型的资源清理(在 C# 中使用 using)或事务或您可能想到的任何其他内容。

唯一不起作用的情况是获取和释放资源分布在程序的不同部分。但如果它是本地化的,如您的示例所示,那么您可以轻松使用这些资源 block 。


顺便说一句:在现代 C# 中,using 实际上是多余的,因为您可以自己实现 Ruby 风格的资源 block :

class File
{
    static T open<T>(string filename, string mode, Func<File, T> block)
    {
        var handle = new File(filename, mode);
        try
        {
            return block(handle);
        }
        finally
        {
            handle.Dispose();
        }
    }
}

// Usage:

File.open("myFile.txt", "w", (file) =>
{
    file.WriteLine(contents);
});

关于ruby-on-rails - 在 Ruby 中开始、拯救和确保?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2191632/

相关文章:

ruby-on-rails - Ruby 语法 : What does the '<' single less than mean in Ruby besides 'less than' ?

css - 内嵌 ruby​​ 样式宽度标签

ruby-on-rails - 没有要加载的文件——thinking-sphinx

ruby-on-rails - 如何使用 Ruby 中哈希的查询参数构造 URI

ruby-on-rails - Brakeman 警告动态渲染路径

ruby-on-rails - 使用 RABL 进行日期格式化

Ruby:引用当前正在执行的 block

c# - 如果您手动检测到线程错误,则抛出适当的异常

java - 获取嵌套属性时没有此类方法异常

java - 奇数格式异常