Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Thành Thạo Xử Lý Lỗi Ruby: Dùng `begin` & `rescue` Quản Lý Exception

Vấn đề thường gặp Ruby là nhận error message, về mặt kỹ thuật gọi là "exceptions". Exception có thể dự đoán được, như file có sẵn lúc nhưng đôi khi thiếu, hoặc API chỉ tạm available do hạn chế, hoặc bất ngờ. Hôm nay bạn học quản lý lỗi dự đoán được. Làm sao? Giới thiệu "begin" & "rescue" Ruby, hai từ khóa quan trọng xử lý điều kiện lỗi. Cách hoạt động? Trước hết hiểu: chương trình Ruby có thể trigger error tại nhiều điểm khi chạy. Ví dụ: Đọc file không tồn tại. Chia số cho 0. Web server làm việc có SSL certificate cũ. Khi lỗi xảy ra... Ruby KHÔNG crash ngay! Bạn có cơ hội recover từ error. Gọi là "exception handling". Ruby cho từ khóa implement error recovery: begin & rescue. Khám phá cách dùng!

Cách Xử Lý Exception Ruby

Bọc code raise exception với block begin / rescue. Cách hoạt động... Phần đầu (begin), có code bạn chạy & có thể raise exception. Ví dụ:

begin
  IO.sysopen('/dev/null')
rescue
  # ...
end 

Ở đây thử mở file với sysopen. Exception raise nếu không mở được. Thời điểm hoàn hảo dùng rescue! Dùng từ khóa này nói điều gì xảy ra khi exception raise. Vậy failure mode dưới kiểm soát. Ví dụ:

begin
  IO.sysopen('/dev/null')
rescue
  puts "Can't open IO device."
end 

Bạn muốn log error & cung cấp default value. Đừng. Bỏ qua. Lỗi.

Rescue Nhiều Exception

Cần biết rescue nhận đối số tùy chọn. Đối số này là lớp exception bạn muốn rescue. Phụ thuộc code bạn chạy. Với IO: Errno::ENOENT cho file thiếu, hoặc Errno::EACCES cho lỗi permission. Phần tốt: Xử lý nhiều exception trong cùng block begin/rescue. Như sau:

begin
  IO.sysopen('/dev/null')
rescue Errno::ENOENT
  puts "File not found."
rescue Errno::EACCES
  puts "Insufficient permissions, not allowed to open file."
end 

Muốn cùng hành động cho nhiều exception... Làm:

begin
  IO.sysopen('/dev/null')
rescue Errno::ENOENT, Errno::EACCES
  puts "There was an error opening the file."
end 

Cách Rescue Exception Bên Trong Block & Method

Không luôn cần begin. Có trường hợp bỏ qua. Ở đâu? Bên trong method & block. Ví dụ:

def get_null_device
  IO.sysopen('/dev/null')
rescue Errno::ENOENT
  puts "Can't open IO device."
end 

Định nghĩa method tự làm việc của begin, nên bỏ qua được. Cũng làm với block. Ví dụ:

["a.txt", "b.txt", "c.txt"].map do |f|
  IO.sysopen(f)
rescue Errno::ENOENT
  puts "Can't open IO device: #{f}."
end 

Còn một cách dùng rescue không begin. Xem cách hoạt động.

Hiểu Inline Rescue & Tại Sao Nguy Hiểm

Dùng rescue inline. Trong vài trường hợp hiếm, dạng này hữu ích. Ví dụ:

["a.txt", "b.txt", "c.txt"].select { |f| File.open(f) rescue nil }.map(&:size) 

Cho mở chỉ file tồn tại & bỏ qua file không. Kết quả nhận size file tồn tại. Không exception raise. Tại sao làm vậy? Giữ code một dòng. Đó là tất cả. Có "nguy hiểm ẩn" khi dùng dạng rescue này vì bắt tất cả exception kế thừa StandardError. Đó là hầu hết exception. Tại sao KHÔNG tốt? Vì tốt nhất chỉ handle exception cụ thể, thay vì chọn rộng. Tránh giấu lỗi từ chính mình! Lỗi ẩn dẫn đến hành vi kỳ lạ & khó debug.

Tóm Tắt

Bạn đã học lỗi Ruby, exception handling cơ bản & từ khóa rescue / begin. Hãy chia sẻ nếu hữu ích 🙂 Cảm ơn bạn đã đọc!