Rubyで開始、救助、保証しますか?質問する

Rubyで開始、救助、保証しますか?質問する

ensureRuby の 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

rescueensureまたはを省略できますelse。また、変数を省略することもできますが、その場合、例外処理コードで例外を検査することはできません。(まあ、グローバル例外変数を使用して、発生した最後の例外にアクセスすることはできますが、少しハッキーです。) また、例外クラスを省略することもできます。その場合、 から継承するすべての例外がStandardErrorキャッチされます。(これはすべての例外がキャッチされるという意味ではないことに注意してください。 のインスタンスであって のインスタンスではExceptionない例外もあるためです。 、、、、、、、、、またはなどの、StandardErrorプログラムの整合性を損なう非常に重大な例外がほとんどです。)SystemStackErrorNoMemoryErrorSecurityErrorNotImplementedErrorLoadErrorSyntaxErrorScriptErrorInterruptSignalExceptionSystemExit

いくつかのブロックは暗黙の例外ブロックを形成します。例えば、メソッド定義は暗黙的に例外ブロックでもあるので、次のように書く代わりに

def foo
  begin
    # ...
  rescue
    # ...
  end
end

あなたはただ書く

def foo
  # ...
rescue
  # ...
end

または

def foo
  # ...
ensure
  # ...
end

class定義や定義についても同様ですmodule

ただし、あなたが尋ねている特定のケースでは、実際にはもっと良いイディオムがあります。一般的に、最後にクリーンアップする必要があるリソースを扱う場合、すべてのクリーンアップを実行するメソッドにブロックを渡してそれを行います。これはusingC# のブロックに似ていますが、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# では、usingRuby スタイルのリソース ブロックを自分で実装できるため、実際には不要です。

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);
});

おすすめ記事