2010-05-14 27 views
5

Tôi đang sử dụng ruby ​​1.8.7.khối ruby ​​và trả lại thứ gì đó từ khối

p = lambda { return 10;} 
def lab(block) 
    puts 'before' 
    puts block.call 
    puts 'after' 
end 
lab p 

Trên đầu ra đang

before 
10 
after 

tôi refactored cùng mã vào đây

def lab(&block) 
    puts 'before' 
    puts block.call 
    puts 'after' 
end 
lab { return 10; } 

Bây giờ tôi nhận được LocalJumpError: trở lại bất ngờ.

Đối với tôi, cả hai mã đều hoạt động tương tự. Có trong trường hợp đầu tiên tôi đi qua một proc và trong trường hợp thứ hai tôi đang đi qua một khối. Nhưng khối & chuyển đổi khối đó thành proc. Vì vậy, proc.call sẽ hành xử giống nhau.

Và vâng tôi đã thấy bài này Using 'return' in a Ruby block

Trả lời

8

Khi bạn vượt qua trong khối với &, bạn đang chuyển đổi nó thành một proc. Điểm quan trọng là một proc và lambda khác nhau (lambda thực sự là một phân lớp của proc), cụ thể là cách chúng xử lý trả về.

Vì vậy, mã refactored của bạn thực sự là tương đương với:

p = Proc.new { return 10;} 
def lab(block) 
    puts 'before' 
    puts block.call 
    puts 'after' 
end 
lab p 

đó cũng tạo ra một LocalJumpError.

Đây là lý do: Trả về của một proc từ phạm vi từ vựng của nó, nhưng lambda trả về phạm vi thực thi của nó. Vì vậy, trong khi lambda trở về lab, thì proc được chuyển vào nó trả về phạm vi bên ngoài mà nó được khai báo. Lỗi nhảy cục bộ có nghĩa là nó không có nơi nào để đi, bởi vì không có chức năng kèm theo.

The Ruby Programming Language nói nó tốt nhất:

Procs have block-like behavior and lambdas have method-like behavior

Bạn chỉ cần theo dõi những gì bạn đang sử dụng ở đâu. Như những người khác đã đề xuất, tất cả những gì bạn cần làm là thả return từ khối của bạn và mọi thứ sẽ hoạt động như dự định.

5

return bên trong một khối sẽ trở lại từ phương pháp khối là trong, không phải từ khối. Để trở về từ việc sử dụng khối next (nó được đặt tên theo cách đó bởi vì với các phương thức vòng lặp như eachmap trở về từ khối về cơ bản có nghĩa là nhảy tới vòng lặp tiếp theo của vòng lặp).

Lưu ý rằng khi giá trị trả lại là biểu thức được đánh giá cuối cùng trong khối, bạn không cần bất kỳ loại báo cáo trả về nào cả, tức là lab { 10 } cũng sẽ thực hiện tương tự.

0

Khối {} bao gồm ngữ cảnh mà nó được đưa ra, vì vậy, return sẽ cố gắng quay lại từ dòng lab { return 10; }. Bạn thực sự có thể thực hiện công việc này (đôi khi thậm chí một cách hữu ích) bằng cách đặt dòng đó bên trong một phương thức, sau đó sẽ trở lại (tức là "sau" không được in).

Để trả lại 10 đến block.call, hãy bỏ qua return (hoặc thay thế next).

0

Tôi nghĩ rằng bạn chỉ cần dereference khối trước khi bạn vượt qua nó:

foo = lambda { return 10 } 

def trace_block(&fn) 
    puts 'before calling fn' 
    puts fn.call 
    puts 'after caling fn' 
end 

trace_block(&foo) 

Output:

before calling fn 
    10 
    after caling fn 

Thông tin thêm:

+0

http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ là một cách viết rất hay. Cảm ơn bạn chia sẻ. –

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