ensure
Ruby の C# に相当するものがあるかどうか気になりました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
例外が発生しない場合でも必ず呼び出されますか?
ベストアンサー1
はい、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
。また、変数を省略することもできますが、その場合、例外処理コードで例外を検査することはできません。(まあ、グローバル例外変数を使用して、発生した最後の例外にアクセスすることはできますが、少しハッキーです。) また、例外クラスを省略することもできます。その場合、 から継承するすべての例外が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
。
ただし、あなたが尋ねている特定のケースでは、実際にはもっと良いイディオムがあります。一般的に、最後にクリーンアップする必要があるリソースを扱う場合、すべてのクリーンアップを実行するメソッドにブロックを渡してそれを行います。これはusing
C# のブロックに似ていますが、Ruby は実際には十分に強力なので、Microsoft の高僧が山から降りてきて、コンパイラを親切に変更してくれるのを待つ必要はありません。Ruby では、自分で実装できます。
# 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# では、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);
});