在Ruby中开始,拯救和确保?

我最近开始使用Ruby进行编程,并且正在寻找异常处理。

我想知道是否ensure在C#中finally的Ruby等价物? 我应该有:

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始终评估代码。 这就是为什么要ensure 。 所以,它finally等于Java和C#的。

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 。大多数非常严重的异常会损害程序的完整性,如SystemStackErrorNoMemoryErrorSecurityErrorNotImplementedErrorLoadErrorSyntaxErrorScriptErrorInterruptSignalExceptionSystemExit 。)

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

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

你只是写

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

要么

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

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

然而,在具体的情况下,你问的是,实际上有一个更好的习惯用法。 一般情况下,当你使用最后需要清理的某些资源时,可以通过将块传递给为您执行所有清理的方法来实现此目的。 它与C#中的using块类似,只是Ruby实际上足够强大,所以不必等待微软的高级牧师从高山上下来,并且为您优雅地更改编译器。 在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 unless filehandle.nil?
end

你知道什么:这已经在核心库中作为File.open 。 但它是一种普遍现象,你可以在自己的代码使用,以及用于实现任何类型的资源清理的(点菜using在C#)或交易或任何其他你可能会想到的。

如果获取和释放资源分布在程序的不同部分,则这种情况不起作用的唯一情况。 但是如果它是本地化的,就像你的例子那样,那么你可以很容易地使用这些资源块。


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

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);
});

仅供参考,即使在rescue部分重新生成异常,在代码执行继续到下一个异常处理程序之前,将执行ensure块。 例如:

begin
  raise "Error!!"
rescue
  puts "test1"
  raise # Reraise exception
ensure
  puts "Ensure block"
end

如果你想确保文件关闭,你应该使用File.open的块格式:

File.open("myFile.txt", "w") do |file|
  begin
    file << "#{content} n"
  rescue
  #handle the error here
  end
end
链接地址: http://www.djcxy.com/p/4395.html

上一篇: Begin, Rescue and Ensure in Ruby?

下一篇: Manually raising (throwing) an exception in Python