Computer >> Máy Tính >  >> Lập trình >> Ruby

Rubys Exception và StandardError:Sự khác biệt là gì?

"Không bao giờ cứu Exception trong Ruby!"

Có thể bạn đã nghe điều này trước đây. Đó là lời khuyên tốt, nhưng nó khá khó hiểu trừ khi bạn đã biết. Hãy chia nhỏ câu lệnh này và xem ý nghĩa của nó.

Bạn có thể biết rằng trong Ruby, bạn có thể giải cứu các trường hợp ngoại lệ như vậy:

begin
  do_something()
rescue => e
  puts e # e is an exception object containing info about the error. 
end

Và bạn có thể giải quyết các lỗi cụ thể bằng cách cung cấp tên lớp của lỗi.

begin
  do_something()
rescue ActiveRecord::RecordNotFound => e
  puts e # Only rescues RecordNotFound exceptions, or classes that inherit from RecordNotFound
end

Mọi loại ngoại lệ trong Ruby chỉ là một lớp. Trong ví dụ trên, ActiveRecord ::RecordNotFound chỉ là tên của một lớp tuân theo các quy ước nhất định.

Điều này rất quan trọng vì khi bạn cứu RecordNotFound , bạn cũng giải cứu mọi ngoại lệ kế thừa từ nó.

Tại sao bạn không nên cứu Exception

Sự cố khi giải cứu Exception là nó thực sự giải cứu mọi ngoại lệ kế thừa từ Exception . Đó là .... tất cả chúng!

Đó là một vấn đề vì có một số ngoại lệ được sử dụng trong nội bộ Ruby. Chúng không liên quan gì đến ứng dụng của bạn và việc nuốt chúng sẽ khiến những điều tồi tệ xảy ra.

Dưới đây là một vài trong số những cái lớn:

  • SignalException ::Ngắt - Nếu bạn giải quyết vấn đề này, bạn không thể thoát ứng dụng của mình bằng cách nhấn Control-c.

  • ScriptError ::SyntaxError - Lỗi cú pháp nuốt có nghĩa là những thứ như puts("Forgot something) sẽ thất bại trong âm thầm.

  • NoMemoryError - Bạn muốn biết điều gì sẽ xảy ra khi chương trình của bạn tiếp tục chạy sau khi nó sử dụng hết RAM? Tôi cũng vậy.

begin
  do_something()
rescue Exception => e
  # Don't do this. This will swallow every single exception. Nothing gets past it. 
end

Tôi đoán rằng bạn không thực sự muốn nuốt bất kỳ ngoại lệ cấp hệ thống nào. Bạn chỉ muốn bắt tất cả các lỗi cấp ứng dụng của mình. Các trường hợp ngoại lệ gây ra mã CỦA BẠN.

May mắn thay, có một cách dễ dàng để thực hiện điều này.

Giải cứu StandardError Thay thế

Tất cả các ngoại lệ mà bạn nên quan tâm kế thừa từ StandardError . Đây là những người bạn cũ của chúng tôi:

  • NoMethodError - nâng lên khi bạn cố gắng gọi một phương thức không tồn tại

  • TypeError - gây ra bởi những thứ như 1 + ""

  • RuntimeError - ai có thể quên RuntimeError cũ tốt?

Để giải cứu những lỗi như thế này, bạn sẽ muốn giải cứu StandardError . Bạn CÓ THỂ làm điều đó bằng cách viết một cái gì đó như sau:

begin
  do_something()
rescue StandardError => e
  # Only your app's exceptions are swallowed. Things like SyntaxErrror are left alone. 
end

Nhưng Ruby đã làm cho nó dễ sử dụng hơn nhiều.

Khi bạn không chỉ định một lớp ngoại lệ nào cả, ruby ​​cho rằng bạn có nghĩa là StandardError. Vì vậy, mã dưới đây giống với mã trên:

begin
  do_something()
rescue => e
  # This is the same as rescuing StandardError
end

Các trường hợp ngoại lệ tùy chỉnh nên kế thừa từ StandardError

Vậy điều này có ý nghĩa gì đối với bạn nếu bạn đang tạo các ngoại lệ tùy chỉnh của riêng mình?

Nó có nghĩa là bạn phải luôn kế thừa từ StandardError và KHÔNG BAO GIỜ khỏi Exception . Kế thừa từ Ngoại lệ là không tốt vì nó phá vỡ hành vi giải cứu mong đợi. Mọi người sẽ nghĩ rằng họ đang giải quyết tất cả các lỗi cấp ứng dụng nhưng của bạn sẽ chỉ vượt qua.

class SomethingBad < StandardError
end

raise SomethingBad

Cây ngoại lệ

Vì các ngoại lệ của Ruby được thực hiện trong một hệ thống phân cấp, nên có thể hữu ích khi xem nó được trình bày. Dưới đây là danh sách các lớp ngoại lệ đi kèm với thư viện chuẩn của Ruby. Đá quý của bên thứ ba như rails sẽ thêm các lớp ngoại lệ bổ sung vào biểu đồ này, nhưng tất cả chúng sẽ kế thừa từ một số lớp trong danh sách này.

Exception
 NoMemoryError
 ScriptError
   LoadError
   NotImplementedError
   SyntaxError
 SignalException
   Interrupt
 StandardError
   ArgumentError
   IOError
     EOFError
   IndexError
   LocalJumpError
   NameError
     NoMethodError
   RangeError
     FloatDomainError
   RegexpError
   RuntimeError
   SecurityError
   SystemCallError
   SystemStackError
   ThreadError
   TypeError
   ZeroDivisionError
 SystemExit
 fatal