Ruby - sự khác nhau giữa Exception và StandardError
"Không bao giờ rescue Exception trong Ruby!" Có lẽ bạn đã nghe điều này từ 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 tạm bỏ qua tuyên bố này và xem ý nghĩa của nó. Bạn có thể biết rằng trong Ruby, bạn có thể rescue các ngoại lệ như vậy: begin ...
"Không bao giờ rescue Exception trong Ruby!"
Có lẽ bạn đã nghe điều này từ 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 tạm bỏ qua tuyên bố này và xem ý nghĩa của nó.
Bạn có thể biết rằng trong Ruby, bạn có thể rescue các ngoại lệ như vậy:
begin do_something() rescue => e puts e # e là một đối tượng exception, nó chưa các thông tin về lỗi. end
Và bạn có thể rescue 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 # Chỉ rescues RecordNotFound exceptions, hoặc là các class thừa kế từ RecordNotFound end
Mỗi loại ngoại lệ trong Ruby chỉ là một class. Trong ví dụ trên, ActiveRecord :: RecordNotFound chỉ là tên của một lớp theo các quy ước nhất định. Điều này rất quan trọng bởi vì khi bạn rescues RecordNotFound, bạn cũng rescue bất kỳ trường hợp ngoại lệ nào được kế thừa từ nó.
Vấn đề với rescues Exception là nó thực sự rescues mọi ngoại lệ được thừa hưởng 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 nội bộ trong Ruby. Chúng không có liên quan gì đến ứng dụng của bạn và nuốt/bắt chúng sẽ gây ra 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 :: Interrupt - Nếu bạn rescues vấn đề này, bạn không thể thoát khỏi ứng dụng bằng cách nhấn control-c.
-
ScriptError :: SyntaxError - Các lỗi cú pháp nuốt/bắt có nghĩa là những thứ như puts ("Quên một cái gì đó") sẽ không thành thục.
-
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 sử dụng hết RAM?
begin do_something() rescue Exception => e # Đừng làm điều này. Điều này sẽ nuốt/bắt mọi ngoại lệ. Không có gì có thể vượt qua được. end
Tôi đoán rằng bạn không thực sự muốn nuốt/bắt bất kỳ các ngoại lệ cấp hệ thống này. Bạn chỉ muốn bắt tất cả các lỗi mức độ ứng dụng của bạn. Các ngoại lệ gây ra bởi code của BẠN.
May mắn thay, có một cách dễ dàng để làm điều này.
Tất cả các ngoại lệ mà bạn nên quan tâm về kế thừa từ StandardError. Đây là những người bạn cũ của chúng tôi:
- NoMethodError - được tạo ra khi bạn cố gọi 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?
Để rescue lỗi như thế này, bạn sẽ muốn rescue StandardError. Bạn CÓ THỂ làm điều đó bằng cách viết một cái gì đó như dưới đây:
begin do_something() rescue StandardError => e # Chỉ những trường hợp ngoại lệ của ứng dụng của bạn bị nuốt/bắt. Những thứ như SyntaxErrror được để lại một mình. end
Nhưng Ruby đã làm cho nó dễ dàng hơn nhiều để sử dụng.
Khi bạn không chỉ định một lớp ngoại lệ nào cả, ruby hình thành đối tượng StandardError. Vì vậy, mã dưới đây là giống với mã trên:
begin do_something() rescue => e # ở đây giống như rescuing StandardError end
Vậy điều này có ý nghĩa gì đối với bạn nếu bạn tạo các ngoại lệ tùy chỉnh của riêng bạn?
Nó có nghĩa là bạn nên luôn kế thừa từ StandardError, và KHÔNG BAO GIỜ từ Exception. Thừa kế từ exception là không tốt vì nó phá vỡ các hành vi mong đợi của rescue. Mọi người sẽ nghĩ rằng họ đang rescue tất cả các lỗi ở cấp độ ứng dụng nhưng bạn sẽ chỉ cần thông qua.
class SomethingBad < StandardError end raise SomethingBad
Vì các trường hợp ngoại lệ của Ruby được thực hiện trong hệ tầng học, nên có thể nhìn thấy nó được đặt ra. 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. Các gem 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
Đây là bài phân tích đơn giản về cách bắt lỗi, so sánh giữa ưu, nhược điểm và phạm vi hoạt động của Exception và StandardError. Bài dịch và mức độ hiểu của tôi có thể chưa được hoàn thiện, mong bạn đọc thông cảm và góp ý. Xin chân thành cảm ơn!!!