Begin, Rescue and Ensure in Ruby?
我最近开始用Ruby编程,我正在研究异常处理。
我想知道,在C语言中,
1 2 3 4 5 6 7 8 9 10 | file = File.open("myFile.txt","w") begin file <<"#{content} " rescue #handle the error here ensure file.close unless file.nil? end |
或者我应该这样做?
1 2 3 4 5 6 7 8 9 10 11 12 | #store the file file = File.open("myFile.txt","w") begin file <<"#{content} " file.close rescue #handle the error here ensure file.close unless file.nil? end |
是否调用
是的,
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
您可以省去
一些块形成隐式异常块。例如,方法定义也是隐式的异常块,因此不是写入
1 2 3 4 5 6 7 | def foo begin # ... rescue # ... end end |
你只写
1 2 3 4 5 | def foo # ... rescue # ... end |
或
1 2 3 4 5 | def foo # ... ensure # ... end |
这同样适用于
但是,在您询问的特定情况下,实际上有一个更好的成语。一般来说,当您处理一些最终需要清理的资源时,可以通过将块传递给一个为您进行所有清理的方法来完成。它类似于c中的
1 2 3 4 5 6 7 8 9 10 11 | # 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语言中,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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); }); |
仅供参考,即使在
1 2 3 4 5 6 7 8 | begin raise"Error!!" rescue puts"test1" raise # Reraise exception ensure puts"Ensure block" end |
如果要确保关闭文件,应使用
1 2 3 4 5 6 7 8 | File.open("myFile.txt","w") do |file| begin file <<"#{content} " rescue #handle the error here end end |
是的,在任何情况下都会调用
是的,
顺便说一下,测试的一个好方法是:
1 2 3 4 5 6 7 8 | begin # Raise an error here raise"Error!!" rescue #handle the error here ensure p"=========inside ensure block" end |
您可以测试在出现异常时是否打印出"==inside-ensure block"。然后,您可以对引发错误的语句进行注释,并通过查看是否打印出任何内容来查看是否执行了
这就是我们需要
1 2 3 4 5 6 7 8 9 10 | def hoge begin raise rescue raise # raise again ensure puts 'ensure' # will be executed end puts 'end of func' # never be executed end |
是的,像