提问人:Lloyd Powell 提问时间:2/3/2010 最后编辑:the Tin ManLloyd Powell 更新时间:7/28/2023 访问量:499070
在 Ruby 中开始、拯救和确保?
Begin, Rescue and Ensure in Ruby?
问:
我最近开始用 Ruby 编程,我正在研究异常处理。
我想知道 Ruby 是否等同于 C#?我应该有: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
答:
是的,在任何情况下都被调用。有关更多信息,请参阅《Ruby 编程》一书的“Exceptions, Catch, and Throw”,并搜索“ensure”。ensure
如果要确保文件已关闭,则应使用以下块形式:File.open
File.open("myFile.txt", "w") do |file|
begin
file << "#{content} \n"
rescue
#handle the error here
end
end
评论
是的,就像保证区块将被执行一样。这对于确保关键资源受到保护非常有用,例如,在出错时关闭文件句柄或释放互斥锁。ensure
finally
评论
File.open
file.close
是的,确保它每次都运行,所以你不需要在块中。ensure
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
是,确保始终评估代码。这就是为什么它被称为 .因此,它等价于 Java 和 C# 的 .ensure
ensure
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
StandardError
Exception
StandardError
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
但是,在您询问的特定情况下,实际上有一个更好的成语。通常,当您使用最后需要清理的某些资源时,您可以通过将块传递给为您完成所有清理的方法来实现。它类似于 C# 中的块,只是 Ruby 实际上足够强大,你不必等待 Microsoft 的大祭司从山上下来,慷慨地为你更改他们的编译器。在 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
这是唯一不起作用的情况,如果获取和释放资源分布在程序的不同部分。但是,如果它是本地化的,如您的示例所示,那么您可以轻松使用这些资源块。
顺便说一句:在现代 C# 中,实际上是多余的,因为你可以自己实现 Ruby 风格的资源块:using
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);
});
评论
ensure
ensure
using
open
using
using
try-finally
仅供参考,即使在该部分中重新引发异常,该块也会在代码执行继续到下一个异常处理程序之前执行。例如:rescue
ensure
begin
raise "Error!!"
rescue
puts "test1"
raise # Reraise exception
ensure
puts "Ensure block"
end
这就是为什么我们需要:ensure
def hoge
begin
raise
rescue
raise # raise again
ensure
puts 'ensure' # will be executed
end
puts 'end of func' # never be executed
end
评论
begin