我最近开始使用 Ruby 进行编程,并且正在研究异常处理。
我想知道ensureRuby 是否相当于finallyC# 中的?我应该有:
ensure
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的,确保始终评估代码。这就是它被称为 的原因ensure。因此,它相当于 Java 和 C# 的finally.
////的大致流程是这样的begin:rescue``else``ensure``end
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
您可以省略rescue,ensure或else。您还可以省略变量,在这种情况下您将无法在异常处理代码中检查异常。(好吧,您总是可以使用全局异常变量来访问引发的最后一个异常,但这有点笨拙。)您可以省略异常类,在这种情况下,所有继承自的异常都StandardError将被捕获。(请注意,这并不意味着 所有 异常都被捕获,因为有些异常是 的实例,Exception但不是StandardError。大多数非常严重的异常会损害程序的完整性,例如SystemStackError, NoMemoryError, SecurityError, NotImplementedError, LoadError, SyntaxError, ScriptError, Interrupt,SignalException或SystemExit。)
rescue
else
StandardError
Exception
SystemStackError
NoMemoryError
SecurityError
NotImplementedError
LoadError
SyntaxError
ScriptError
Interrupt
SignalException
SystemExit
一些块形成隐式异常块。例如,方法定义也是隐式的异常块,所以不要写
def foo begin # ... rescue # ... end end
你只写
def foo # ... rescue # ... end
要么
def foo # ... ensure # ... end
这同样适用于class定义和module定义。
class
module
但是,在您询问的特定情况下,实际上有一个更好的习语。通常,当您使用一些最终需要清理的资源时,您可以通过将块传递给为您完成所有清理的方法来实现。它类似于usingC# 中的块,除了 Ruby 实际上足够强大,您不必等待微软的大祭司从山上下来并为您慷慨地更改他们的编译器。在 Ruby 中,您可以自己实现它:
using
# 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. 但它是一种通用模式,您也可以在自己的代码中使用,以实现任何类型的资源清理(usingC# 中的脿 la)或事务或您可能想到的任何其他方式。
File.open
如果获取和释放资源分布在程序的不同部分,那么这不起作用的唯一情况。但是,如果它是本地化的,如您的示例中那样,那么您可以轻松地使用这些资源块。
顺便说一句:在现代 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); });