Ruby có hai cơ chế ngoại lệ khác nhau: Ném / Bắt và Nâng / Cứu.
Tại sao chúng ta có hai?
Khi nào bạn nên sử dụng cái này chứ không phải cái kia?
Ruby có hai cơ chế ngoại lệ khác nhau: Ném / Bắt và Nâng / Cứu.
Tại sao chúng ta có hai?
Khi nào bạn nên sử dụng cái này chứ không phải cái kia?
Câu trả lời:
Tôi nghĩ rằng http://hasno.info/ruby-gotchas-and-caveats có một lời giải thích hợp lý về sự khác biệt:
bắt / ném không giống như nâng / cứu. bắt / ném cho phép bạn nhanh chóng thoát khỏi các khối trở lại điểm mà một điểm bắt được xác định cho một biểu tượng cụ thể, nâng cao cứu hộ là công cụ xử lý ngoại lệ thực sự liên quan đến đối tượng Ngoại lệ.
raise
rất tốn kém. throw
không phải. Hãy nghĩ về throw
việc sử dụng goto
để thoát khỏi một vòng lặp.
raise
, fail
, rescue
, Và ensure
xử lý sai sót , hay còn gọi là trường hợp ngoại lệthrow
và catch
là dòng điều khiểnKhông giống như trong các ngôn ngữ khác, ném và bắt của Ruby không được sử dụng cho các trường hợp ngoại lệ. Thay vào đó, họ cung cấp một cách để chấm dứt thực hiện sớm khi không cần làm thêm. (Grimm, 2011)
Việc chấm dứt một cấp điều khiển duy nhất, như một while
vòng lặp, có thể được thực hiện một cách đơn giản return
. Chấm dứt nhiều cấp độ của luồng điều khiển, như một vòng lặp lồng nhau, có thể được thực hiện với throw
.
Mặc dù cơ chế ngoại lệ của nâng và cứu là tuyệt vời để từ bỏ thực thi khi có sự cố, đôi khi thật tuyệt khi có thể nhảy ra khỏi một số cấu trúc được lồng sâu trong quá trình xử lý thông thường. Đây là nơi bắt và ném có ích. (Thomas và Hunt, 2001)
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise cung cấp một lời giải thích tuyệt vời mà tôi nghi ngờ tôi có thể cải thiện. Để tóm tắt, đặt biệt danh cho một số mẫu mã từ bài đăng trên blog khi tôi đi:
raise
/ rescue
là những từ tương tự gần nhất với throw
/ catch
xây dựng mà bạn quen thuộc với các ngôn ngữ khác (hoặc với Python's raise
/ except
). Nếu bạn gặp phải một điều kiện lỗi và bạn sẽ khắc throw
phục nó bằng ngôn ngữ khác, bạn nên sử dụng raise
Ruby.
Ruby's throw
/ catch
cho phép bạn phá vỡ sự thực thi và trèo lên ngăn xếp tìm kiếm catch
(như raise
/ rescue
không), nhưng thực sự không có nghĩa đối với các điều kiện lỗi. Nó nên được sử dụng hiếm khi và chỉ có khi hành vi "đi lên ngăn xếp cho đến khi bạn tìm thấy một catch
hành vi tương ứng " có ý nghĩa đối với thuật toán bạn đang viết nhưng sẽ không có ý nghĩa gì khi nghĩ về throw
lỗi tương ứng với lỗi tình trạng.
Bắt và ném được sử dụng trong Ruby là gì? cung cấp một số gợi ý về việc sử dụng tốt đẹp của throw
/ catch
xây dựng.
Sự khác biệt hành vi cụ thể giữa chúng bao gồm:
rescue Foo
sẽ giải cứu các trường hợp Foo
bao gồm các lớp con của Foo
. catch(foo)
sẽ chỉ bắt cùng một đối tượngFoo
,. Bạn không chỉ không thể vượt qua catch
một tên lớp để bắt các trường hợp của nó, mà thậm chí nó sẽ không thực hiện so sánh bình đẳng. Ví dụ
catch("foo") do
throw "foo"
end
sẽ cung cấp cho bạn UncaughtThrowError: uncaught throw "foo"
(hoặc một ArgumentError
phiên bản Ruby trước 2.2)
Nhiều điều khoản giải cứu có thể được liệt kê ...
begin
do_something_error_prone
rescue AParticularKindOfError
# Insert heroism here.
rescue
write_to_error_log
raise
end
trong khi nhiều catch
es cần được lồng ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
end
end
Một trần rescue
là tương đương rescue StandardError
và là một cấu trúc thành ngữ. Một "trần catch
", như catch() {throw :foo}
, sẽ không bao giờ bắt được bất cứ thứ gì và không nên được sử dụng.
goto
trong C / C ++ như @docwhat đã đề cập, Java đã dán nhãn break và continue . (Python cũng có một đề xuất bị từ chối cho việc này.)