Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

어떤 예외를 잡아야 하는지 알기 위한 우아한 트릭을 구출하다

이전에 Ruby의 예외로 작업한 적이 있다면 어떤 예외가 구제되고 어떤 예외가 발생하지 않는지 지정할 수 있습니다.

begin
  raise ArgumentError
rescue ArgumentError
  # Rescues the `ArgumentError`
end

... "부모"를 구하면 모든 "자식"도 구한다는 것을 알고 있을 것입니다.

begin 
  raise ArgumentError
rescue StandardError
  # Rescues `ArgumentError`, because it inherits from 
  # `StandardError`
end

내가 "부모"와 "자식"이라고 말할 때 나는 단순히 클래스 상속을 언급하고 있습니다. Ruby 소스 코드 깊숙한 곳에 다음과 같은 내용이 있습니다.

class ArgumentError < StandardError
   ...
end

흥미로운 트릭

여기 내 질문이 있습니다. Ruby는 지정된 예외가 지정한 클래스에서 상속되는지 어떻게 알 수 있나요?

가장 확실한 접근 방식은 is_a?를 사용하는 것입니다. 또는 kind_of? 방법. 다음과 같이 상상할 수 있습니다.

if the_exception.is_a?(StandardError)
   # do the rescue
end

하지만 그런 일은 일어나지 않습니다. 대신 Ruby는 더 흥미로운 ===를 사용합니다. 운영자.

if StandardError === the_exception
   # do the rescue
end

a === b를 사용한 적이 없는 경우 , 일반적으로 "본질적으로 b로 정의된 그룹에 속합니까?"라는 질문에 대답합니다. 다음은 몇 가지 예입니다.

(1..10) === 5             # true
('a'..'f') === "z"        # false

String === "hello"        # true
String === 1              # false

/[0-9]{3}/ === "hello123" # true
/[0-9]{3}/ === "hello"    # false

===이기 때문에 == 와 같은 일반적인 루비 메서드입니다. , 직접 정의할 수 있습니다.

class RedThings
   def self.===(thing)
     thing.color == :red
   end
end

그래서, 우리는 무엇을 알고 있습니까? 우리는 rescue === 사용 어떤 예외가 구출되는지 확인합니다. 그리고 우리는 우리 자신의 ===를 정의할 수 있다는 것을 압니다. 방법. 즉, 어떤 예외가 구조되는지 즉석에서 결정하는 클래스를 만들 수 있습니다.

class SevereMatcher
  def self.===(exception)
    exception.message =~ /severe/    
  end
end

begin
  raise RuntimeError, "Something severe happened"
rescue SevereMatcher
  # rescues all exceptions with the word "severe" in
  # the message, regardless of class.
end

이 트릭을 알고 나면 유일한 한계는 상상력입니다.

결론

인정합니다. 동적 예외 매처를 생성할 필요가 없을 수도 있습니다. 그러나 이것은 === kind_of? 대신 Ruby를 훨씬 더 유연하고 흥미롭게 만듭니다.