Khi viết các thuật toán đệ quy mà hành động dựa trên cấu trúc dữ liệu lồng nhau sử dụng các hàm đệ quy, bạn có thể sử dụng throw
tương tự như cách bạn sẽ sử dụng một break
hoặc đầu return
khi viết các thuật toán lặp đi lặp lại rằng hành động trên dữ liệu phẳng bằng for
vòng.
Ví dụ, giả sử rằng bạn có một danh sách các số nguyên dương và bạn muốn (đối với một số lý do) để viết một hàm trả về true nếu một trong các điều kiện sau đây được đáp ứng:
- Tổng số tất cả các yếu tố trong danh sách là lớn hơn 100
- một số phần tử trong danh sách nếu bằng 5
Hãy nói cũng rằng bạn luôn muốn thực hiện việc kiểm tra này trong một duy nhất, ngắn mạch đường chuyền qua danh sách, thay vì làm một số reduce
c tất cả để có được số tiền và một cuộc gọi any?
riêng biệt để tìm kiếm fives.
Có thể bạn muốn viết một số mã một chút như thế này (thực sự, có lẽ bạn đã viết code như thế này trong một số ngôn ngữ tại một số điểm trong cuộc sống của bạn):
def test(list)
sum = 0
for i in list
sum += i
if i == 5 || sum > 100
return true
end
end
return false
end
Trong hầu hết các ngôn ngữ, không có tương đương sạch để loại bỏ thuật toán đệ quy sử dụng hàm đệ quy. Trong Ruby, mặc dù, có! Giả sử rằng, thay vì có danh sách và muốn kiểm tra xem các phần tử của nó có chứa năm hoặc tổng thành hơn 100 hay không, bạn có một cây và muốn kiểm tra xem lá của mình có chứa năm hoặc tổng trên 100 hay không -circuiting và trở lại ngay sau khi bạn biết câu trả lời.
Bạn có thể làm điều này thanh lịch với throw
/catch
, như thế này:
def _test_recurse(sum_so_far, node)
if node.is_a? InternalNode
for child_node in node.children
sum_so_far = _test_recurse(sum_so_far, child_node)
end
return sum_so_far
else # node.is_a? Leaf
sum_so_far += node.value
if node.value == 5
throw :passes_test
elsif sum_so_far > 100
throw :passes_test
else
return sum_so_far
end
end
end
def test(tree)
catch (:passes_test) do
_test_recurse(0, tree)
return false
end
return true
end
Các throw :passes_test
đây đóng vai trò giống như một break
; nó cho phép bạn nhảy ra khỏi toàn bộ ngăn xếp cuộc gọi của bạn bên dưới cuộc gọi _test
ngoài cùng bên ngoài. Trong các ngôn ngữ khác, bạn có thể làm điều này bằng cách lạm dụng ngoại lệ cho mục đích này hoặc bằng cách sử dụng một số mã trả về để báo cho hàm đệ quy ngừng đệ quy, nhưng điều này trực tiếp và đơn giản hơn.
Bản sao có thể có của: http://stackoverflow.com/questions/51021/what-is-the-differance-between-raising-exceptions-vs-throwing-exceptions-in-ruby – Shadwell