Một ngoại lệ đã nâng có thể được cứu để ngăn ứng dụng của bạn gặp sự cố khi nó lên đến đầu ngăn xếp cuộc gọi. Trong Ruby, chúng tôi sử dụng rescue
từ khóa cho điều đó.
Khi giải cứu một ngoại lệ trong Ruby, bạn có thể chỉ định một lớp lỗi cụ thể sẽ được giải cứu khỏi.
begin
raise 'This exception will be rescued!'
rescue StandardError => e
puts "Rescued: #{e.inspect}"
end
Lưu ý :Khi sử dụng raise
mà không chỉ định một lớp ngoại lệ, Ruby sẽ mặc định là RuntimeError
.
Bên cạnh việc chỉ định một lớp ngoại lệ duy nhất để giải cứu, bạn có thể chuyển một mảng các lớp ngoại lệ vào rescue
từ khóa. Điều này sẽ cho phép bạn phản hồi nhiều lỗi theo cùng một cách.
begin
raise 'This exception will be rescued!'
rescue StandardError, AnotherError => e
puts "Rescued: #{e.inspect}"
end
Nhiều rescue
các khối có thể được sử dụng để xử lý các lỗi khác nhau theo những cách khác nhau. Điều này có thể hữu ích khi làm việc với một thư viện tạo ra các ngoại lệ khác nhau cho các tình huống khác nhau.
begin
raise 'This exception will be rescued!'
rescue StandardError => e
puts "Rescued: #{e.inspect}"
rescue AnotherError => e
puts "Rescued, but with a different block: #{e.inspect}"
end
Phân cấp ngoại lệ
Hệ thống phân cấp ngoại lệ của Ruby được sử dụng để phân biệt giữa các loại lỗi khác nhau, đồng thời cung cấp cho bạn khả năng giải cứu khỏi một nhóm lỗi mà không cần chỉ định tất cả chúng.
Mặc dù các thư viện có thể định nghĩa các lớp con ngoại lệ của riêng chúng, nhưng danh sách các lớp con ngoại lệ được tích hợp sẵn trên Ruby 2.5 trông giống như sau:
- NoMemoryError
- ScriptError
- LoadError
- NotImplementedError
- SyntaxError
- SecurityError
- SignalException
- Interrupt
- StandardError (default for `rescue`)
- ArgumentError
- UncaughtThrowError
- EncodingError
- FiberError
- IOError
- EOFError
- IndexError
- KeyError
- StopIteration
- LocalJumpError
- NameError
- NoMethodError
- RangeError
- FloatDomainError
- RegexpError
- RuntimeError (default for `raise`)
- SystemCallError
- Errno::*
- ThreadError
- TypeError
- ZeroDivisionError
- SystemExit
- SystemStackError
- fatal (impossible to rescue)
Khi bỏ qua lớp ngoại lệ trong rescue
khối, StandardError
được giả định. Bởi vì ArgumentError
và NoMethodError
là các lớp con của StandardError
, chúng sẽ được giải cứu khi chúng xuất hiện trong khối.
Một ví dụ điển hình về cách hoạt động của hệ thống phân cấp ngoại lệ là SystemCallError
, là một lớp ngoại lệ phụ thuộc vào nền tảng cấp thấp. Nó được nhìn thấy thường xuyên nhất khi đọc hoặc ghi vào tệp.
Ruby’s File.read
phương thức sẽ đưa ra một ngoại lệ nếu nó không đọc được tệp. Điều đó có thể xảy ra vì một số lý do, chẳng hạn như tệp không tồn tại hoặc chương trình không có quyền chính xác để đọc nó.
Vì những vấn đề này phụ thuộc vào nền tảng, nên Ruby có thể đưa ra các ngoại lệ khác nhau tùy thuộc vào loại hệ điều hành đang chạy trên máy. Đối với các lỗi cấp thấp như thế này, Ruby triển khai một danh sách khác gồm Errno::*
-các ngoại lệ cho mỗi nền tảng.
Tất cả Errno::*
này ngoại lệ là các lớp con của SystemCallError
. Mặc dù chúng dành riêng cho nền tảng, chúng vẫn có thể được sử dụng trong rescue
chặn bằng cách giải cứu khỏi SystemCallError
.
begin
File.read("does/not/exist")
rescue SystemCallError => e
puts "Rescued: #{e.inspect}"
end
Nuốt ngoại lệ
Thông thường, tốt nhất là càng cụ thể càng tốt khi giải cứu các trường hợp ngoại lệ, để ngăn việc vô tình nuốt các trường hợp ngoại lệ.
Cứu hộimage = nil
begin
File.read(image.filename)
rescue
puts "File can't be read!"
end
Trong ví dụ này, image
biến là nil
, vì vậy nó tạo ra một NoMethodError
khi chúng tôi cố gắng gọi #filename
trên đó (NoMethodError: undefined method `filename' for nil:NilClass
). Bởi vì mọi StandardError
lớp con được giải cứu khỏi (bao gồm NoMethodError
), ngoại lệ bị nuốt và thông báo “Không thể đọc tệp!” - được in. Điều này ẩn một lỗi có thể xảy ra trong mã.
Lưu ý :Mặc dù có thể, nhưng sử dụng Exception
lớp cha trong rescue
khối rất không được khuyến khích.
Bạn có bất kỳ câu hỏi nào về việc nâng cao hoặc giải cứu các trường hợp ngoại lệ trong Ruby? Vui lòng cho chúng tôi biết tại @AppSignal. Tất nhiên, chúng tôi muốn biết bạn thích bài viết này như thế nào hoặc nếu bạn có chủ đề khác mà bạn muốn biết thêm.