2010-06-15 10 views
5

Hãy nói rằng tôi có một hàmcủa Ruby Enumerable đồ Hiểu # (với các khối phức tạp hơn)

def odd_or_even n 
    if n%2 == 0 
    return :even 
    else 
    return :odd 
    end 
end 

Và tôi đã có một mảng đếm đơn giản

simple = [1,2,3,4,5] 

Và tôi chạy nó thông qua bản đồ, với tôi chức năng, sử dụng khối do-end:

simple.map do 
    |n| odd_or_even(n) 
end 
# => [:odd,:even,:odd,:even,:odd] 

Làm cách nào để xác định hàm này ngay từ đầu? Ví dụ:

# does not work 
simple.map do |n| 
    if n%2 == 0 
    return :even 
    else 
    return :odd 
    end 
end 

# Desired result: 
# => [:odd,:even,:odd,:even,:odd] 

không hợp lệ, và trình biên dịch tức giận với tôi vì thậm chí còn nghĩ về nó. Nhưng làm thế nào tôi sẽ thực hiện một loại tương đương của điều, mà hoạt động?

chỉnh sửa

Trên thực tế, giải pháp cho vấn đề của tôi quan trọng đối với tôi ít hơn rất nhiều so với động cơ/lý do đằng sau nó, để giúp tôi hiểu thêm cách khối ruby ​​làm việc :)

+2

Đối với những gì nó có giá trị, bạn có thể làm được không? hoặc 1.odd? trong ruby> = 1.8.7 – steenslag

Trả lời

13

Bạn' lại gần quá. Chỉ cần loại bỏ các return s và bạn đang vàng.

Điều này là do khối được chuyển đến map là một proc (tức là được tạo với Proc.new) và không phải là lambda. Một return trong một proc không chỉ nhảy ra khỏi proc nó nhảy ra khỏi phương thức được thực hiện (tức là gọi là call trên) proc. Một sự trở lại trong một lambda, mặt khác, nhảy ra khỏi chỉ lambda.

Phương thức proc trả về một lambda trong Ruby 1.8 và một Proc trong Ruby 1.9. Tốt nhất là không nên sử dụng phương pháp này và rõ ràng với cấu trúc nào bạn muốn sử dụng.

Tôi đoán bạn đang ở trong IRB hoặc một tập lệnh ruby ​​đơn giản khi bạn đang dùng thử.

a = Proc.new { return } 
a.call # fails. Nothing to return from. 

def foobar 
    a = Proc.new { return } 
    a.call 
    puts 'hello' # not reached. The return within the proc causes execution to jump out of the foobar method. 
end 
foobar # succeeds, but does not print 'hello'. The return within the proc jumps out of the foobar method. 

b = lambda { return } 
b.call # succeeds. The return only returns from the lambda itself. 

def bazquux 
    b = lambda { return } 
    b.call 
    puts 'hello' # this is reached. The lambda only returned from itself. 
end 
bazquux # succeeds, and prints 'hello' 

Bài học để học hỏi từ điều này là sử dụng trả về tiềm ẩn trừ khi bạn không thể, tôi đoán vậy.

+0

Có lý do gì không * tại sao điều này xảy ra? Liệu khối lệnh có đơn giản đưa ra lệnh được thực thi cuối cùng, như trong các trả về ngầm không? Tôi hỏi điều này vì tôi muốn có thể dự đoán điều gì xảy ra; có những thứ này có vẻ hơi ... ngẫu nhiên. –

+0

Phiên bản ngắn gọn là "đó là một trong những khác biệt giữa procs và lambdas." Làm việc trên một lời giải thích tốt hơn. Và có, các khối sẽ chỉ trả lại biểu thức được đánh giá gần đây nhất trong chúng. – x1a4

+0

cảm ơn lời giải thích; nó rất kỹ lưỡng và hữu ích =) chỉ là một câu hỏi cuối cùng ... là nó có thể vượt qua một lambda như là một khối? #map, có lẽ? –

9

tôi nghi ngờ đây có thể là một câu hỏi trùng lặp, nhưng để đưa ra một giá trị ra khỏi một khối, sử dụng next

simple.map do |n| 
    if n%2 == 0 
    next :even 
    else 
    next :odd 
    end 
end 
+0

hm, điều này có vẻ là chính xác những gì tôi đang tìm kiếm :) cảm ơn :) –

3

biến Shortest sử dụng Andrew câu trả lời:

simple.map { |n| next :even if n % 2 == 0; :odd } 
+1

Mang nó một bước xa hơn:' simple.map {| n | tiếp theo n% 2 == 0? : even:: odd} ';-) –

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