[ruby-on-rails] 구조, 시작과 루비 확인?

최근에 Ruby로 프로그래밍을 시작했으며 예외 처리를보고 있습니다.

C #에서 ensureRuby와 동등한 지 궁금합니다 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상관없이 예외가 발생되지 않은 경우에도 무엇을 호출되지 얻을?



답변

예, 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루비는 실제로 Microsoft의 대제사장이 산에서 내려 와서 컴파일러를 자비 롭게 바꿀 때까지 기다릴 필요가 없을 정도로 강력하다는 점을 제외하면 C # 의 블록 과 비슷 합니다. 루비에서는 직접 구현할 수 있습니다.

# 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

그리고 무엇을 알고 있습니까 : 이것은 이미 코어 라이브러리에서로 사용할 수 있습니다 File.open. 그러나 모든 종류의 리소스 정리 ( usingC #에서 la ) 또는 트랜잭션 또는 생각할 수있는 모든 것을 구현하기 위해 자신의 코드에서도 사용할 수있는 일반적인 패턴 입니다.

리소스를 확보하고 해제하는 것이 프로그램의 다른 부분에 분산되어있는 경우 이것이 작동하지 않는 유일한 경우입니다. 그러나 예제와 같이 현지화 된 경우 이러한 리소스 블록을 쉽게 사용할 수 있습니다.


BTW : 현대 C #에서는 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);
});


답변

참고로, rescue섹션 에서 예외가 다시 발생 ensure하더라도 코드 실행이 다음 예외 핸들러로 계속 진행되기 전에 블록이 실행됩니다. 예를 들어 :

begin
  raise "Error!!"
rescue
  puts "test1"
  raise # Reraise exception
ensure
  puts "Ensure block"
end


답변

파일을 닫으려면 다음 형식의 블록을 사용해야합니다 File.open.

File.open("myFile.txt", "w") do |file|
  begin
    file << "#{content} \n"
  rescue
  #handle the error here
  end
end


답변

예, ensure어떤 상황에서도 부름을받습니다. 자세한 정보 는 Programming Ruby 서적의 ” 예외, 캐치 및 처리 “를 참조하고 “확인”을 검색하십시오.


답변

예, ensure매번 실행되므로 블록 file.close에서 필요하지 않습니다 begin.

그런데 테스트하는 좋은 방법은 다음과 같습니다.

begin
  # Raise an error here
  raise "Error!!"
rescue
  #handle the error here
ensure
  p "=========inside ensure block"
end

예외가있을 때 “========= 내부 블록 확인”이 인쇄되는지 테스트 할 수 있습니다. 그런 다음 오류를 발생시키는 명령문을 주석 처리하고 ensure인쇄 된 것이 있는지 확인하여 명령문이 실행되는지 확인할 수 있습니다.


답변

이것이 우리에게 필요한 이유입니다 ensure.

def hoge
  begin
    raise
  rescue
    raise # raise again
  ensure
    puts 'ensure' # will be executed
  end
  puts 'end of func' # never be executed
end  


답변

예, ensure같은 finally 보장 블록이 실행됩니다 . 이는 오류시 파일 핸들을 닫거나 뮤텍스를 해제하는 등 중요한 리소스를 보호하는 데 매우 유용합니다.