Ensure
无论是否发生异常(Exception),你可能会在某些情况下采取某些特定操作。例如,每当你处理某种不可预测的输入/输出时 - 例如,在使用磁盘上的文件和目录时 - 总是有可能位置(磁盘或目录)或数据源(文件)根本不存在或者可能发生其它类型的问题 - 例如当你尝试写入时磁盘已满,或者尝试读取时可能包含一个错误类型的数据。
无论你是否遇到任何问题,你可能需要执行一些最终的“清理”(cleanup)过程 - 例如登录到特定的工作目录或关闭先前打开的文件。你可以通过在 begin..rescue
代码块后跟随一个以 ensure
关键字开头的另一个块的来执行此操作。ensure
块中的代码将始终会执行 - 无论之前是否发生异常。
最后,我想确保我的工作目录(由 Dir.getwd
提供)始终恢复到其原始位置。我通过在 startdir
变量中保存原始目录并再次在 ensure
块中将其作为工作目录来完成此操作:
startdir = Dir.getwd
begin
Dir.chdir( "X:\\" )
puts( `dir` )
rescue Exception => e
puts e.class
puts e
ensure
Dir.chdir( startdir )
end
现在让我们看看如何处理从文件中读取错误数据的问题。如果数据损坏,或者你不小心打开了错误的文件,或者很简单 - 你的程序代码包含错误(bug)时,则可能会发生这种情况。
这里我有一个文件 test.txt,包含六行内容。前五行是数字(numbers);第六行不是。我的代码会打开此文件并读入所有六行内容:
f = File.new( "test.txt" )
begin
for i in (1..6) do
puts("line number: #{f.lineno}")
line = f.gets.chomp
num = line.to_i
puts( "Line '#{line}' is converted to #{num}" )
puts( 100 / num )
end
rescue Exception => e
puts( e.class )
puts( e )
ensure
f.close
puts( "File closed" )
end
这些行作为字符串读入(使用 gets
),尝试将它们转换为整数(使用 to_i
)。转换失败时不会产生错误;Ruby 会返回值 0。
问题出现在下一行代码中,它尝试按转换后的数字进行除法运算。输入文件的第六行包含字符串 “six”,当尝试转换为整数时产生 0 - 并且当在除法运算中使用该值时不可避免地会导致错误发生。
在外部打开数据文件后,无论是否发生错误我都想确保文件会关闭。例如,如果我只通过将 for
循环中的范围编辑为 (1..5)
来读取前五行,那么就没有异常。我仍然想要关闭该文件。
但是将文件关闭代码(f.close
)放在 rescue
子句中并不好,因为在这种情况下它不会被执行。然而,通过将它放在 ensure
子句中,无论是否发生异常,我都可以确定该文件将被关闭。