Ruby - sự khác nhau giữa Exception và StandardError
Bài đăng này đã không được cập nhật trong 6 năm
"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ó.
Tại sao bạn không nên rescue Exception
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.
Rescue StandardError Như là giải pháp thay thế
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
Nếu Custom Exceptions bạn nên thừa kế từ StandardError
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
Cây Exception
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
Kết Luận
Đâ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!!!
All rights reserved