我最近开始使用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
是否会被调用?
答案 0 :(得分:1108)
是的,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
您可以省略rescue
,ensure
或else
。您也可以省略变量,在这种情况下,您将无法在异常处理代码中检查异常。 (好吧,你总是可以使用全局异常变量来访问引发的最后一个异常,但这有点像hacky。)而且你可以省略异常类,在这种情况下,所有异常继承自StandardError
会被抓住。 (请注意,这并不意味着会捕获所有异常,因为有些例外是Exception
但不是StandardError
的实例。大多数非常严重的异常都会影响完整性该计划包括SystemStackError
,NoMemoryError
,SecurityError
,NotImplementedError
,LoadError
,SyntaxError
,ScriptError
,{{1 }},Interrupt
或SignalException
。)
某些块形成隐式异常块。例如,方法定义也隐含地也是异常块,因此不是编写
SystemExit
你写的只是
def foo
begin
# ...
rescue
# ...
end
end
或
def foo
# ...
rescue
# ...
end
这同样适用于def foo
# ...
ensure
# ...
end
定义和class
定义。
然而,在您询问的具体案例中,实际上有一个更好的习语。通常,当您使用某些需要在最后清理的资源时,可以通过将块传递给为您执行所有清理的方法来实现。它类似于C#中的module
块,除了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
的形式提供。但它是一种通用模式,您也可以在自己的代码中使用,用于实现任何类型的资源清理(在C#中使用File.open
}或事务或您可能想到的任何其他内容。
唯一不起作用的情况,如果获取和释放资源分布在程序的不同部分。但如果它是本地化的,如在您的示例中,那么您可以轻松使用这些资源块。
using
实际上是多余的,因为你可以自己实现Ruby风格的资源块:
using
答案 1 :(得分:33)
仅供参考,即使在rescue
部分中重新引发异常,也会在代码执行继续执行下一个异常处理程序之前执行ensure
块。例如:
begin
raise "Error!!"
rescue
puts "test1"
raise # Reraise exception
ensure
puts "Ensure block"
end
答案 2 :(得分:13)
如果您想确保文件已关闭,则应使用File.open
的块形式:
File.open("myFile.txt", "w") do |file|
begin
file << "#{content} \n"
rescue
#handle the error here
end
end
答案 3 :(得分:6)
是的,在任何情况下都会调用ensure
。有关更多信息,请参阅Programming Ruby书籍的“Exceptions, Catch, and Throw”并搜索“ensure”。
答案 4 :(得分:4)
是的,ensure
ENSURES每次都会运行,因此您不需要file.close
块中的begin
。
顺便说一下,测试的一个好方法是:
begin
# Raise an error here
raise "Error!!"
rescue
#handle the error here
ensure
p "=========inside ensure block"
end
您可以测试是否在出现异常时打印出“========= inside ensure block”。
然后,您可以注释掉引发错误的语句,并查看是否通过查看是否有任何内容被执行来执行ensure
语句。
答案 5 :(得分:3)
是的,ensure
赞finally
保证会执行该块。这对于确保关键资源受到保护非常有用,例如:错误时关闭文件句柄或释放互斥锁。
答案 6 :(得分:3)
这就是我们需要ensure
:
def hoge
begin
raise
rescue
raise # raise again
ensure
puts 'ensure' # will be executed
end
puts 'end of func' # never be executed
end