2015-04-02 14 views
5
def foo 
    puts "in foo" 
    s = yield 
    puts "s = #{s}" 
    return 2 
ensure 
    puts "in ensure" 
    return 1 
end 

def bar 
    foo do 
    puts "in bar block" 
    return 3 
    end 
    return 4 
end 


[36] pry(main)> r = bar 
in foo 
in bar block 
in ensure 
=> 4 

Tôi mong đợi r = 3 nhưng hóa ra là r = 4. Nếu tôi xóa mã đảm bảo, r = 3 được mong đợi. Tại sao lại như vậy?Trả lại Ruby trong khối lợi nhuận được gọi từ phương thức có đảm bảo

def foo 
    puts "in foo" 
    s = yield 
    puts "s = #{s}" 
    return 2 
end 

r = bar 
in foo 
in bar block 
=> 3 
+1

[blog] này (http://railsware.com/blog/2012/11/20/yield-gotcha-in-ruby-blocks/) được cố gắng giải thích cho bạn .. những gì đang xảy ra .. –

Trả lời

3

Tính năng của Ruby là "tháo ngăn xếp" khỏi các khối. Cách hoạt động của bạn trở lại theo từng bước:

  1. Bạn trả lại 3 từ số bar khối. return_value = 3 và Ruby đánh dấu rằng nó là một giá trị trả về từ khối, do đó, nó sẽ giải phóng ngăn xếp và trả về 3 từ hàm cha. Nó sẽ không quay trở lại foo nếu không có phần ensure. Nó là sự khác biệt rất quan trọng giữa việc trở về từ các hàm và từ các khối.
  2. Nhưng Ruby luôn thực hiện ensure và có thêm return trong mục ensure của foo.
  3. Sau return 1 trong ensure phần của foo, return_value là 1. Nó không phải là một giá trị từ khối, vì vậy Ruby "quên" về trước return 3 và quên trả lại nó từ bar.
  4. Nó trả về 1 từ foo4 từ bar.

Hơn nữa, nếu bạn viết next 3 thay vì return 3 trong khối - nó sẽ trở lại sau khi fooyield và thực hiện puts "s = #{s}"; return 2 thậm chí không có khối đảm bảo. Đây là một tính năng huyền diệu của Ruby cho các trình lặp và các điều tra viên.

Các vấn đề liên quan