2011-04-05 23 views
5

Tôi gặp sự cố khi nhận biến từ vòng lặp for. Có vẻ như i (var) được tính sau này và không phải là định nghĩa lớp mà tôi hoàn toàn yêu cầu.define_method không sử dụng biến cho đến khi phương thức được gọi?

ree-1.8.7-2010.02 > class Pat 
ree-1.8.7-2010.02 ?> for i in 39..47 
ree-1.8.7-2010.02 ?> define_method("a#{i}".to_sym) do 
ree-1.8.7-2010.02 >   puts i 
ree-1.8.7-2010.02 ?>  end 
ree-1.8.7-2010.02 ?> end 
ree-1.8.7-2010.02 ?> end 
#=> 39..47 

ree-1.8.7-2010.02 > p = Pat.new 
#=> #<Pat:0x103c31140> 

ree-1.8.7-2010.02 > p.a39 
47 
#=> nil 

ree-1.8.7-2010.02 > p.a49 
NoMethodError: undefined method `a49' for #<Pat:0x103c31140> 
    from (irb):69 
    from :0 
ree-1.8.7-2010.02 > p.a40 
47 
#=> nil 

Tôi có nên sử dụng def? nếu vậy làm thế nào tôi có thể đạt được các tên phương pháp năng động mà tôi đạt được ở đây với def.

Trả lời

7

gì đang xảy ra có một chút tinh tế ... truyền thống cho vòng lặp mà bạn đang sử dụng cổ phần biến "i" duy nhất trên tất cả các lần lặp ... Việc đóng (mật khẩu khối để define_method) là bắt "i" - và vì chỉ có một "i", chúng sẽ tất cả (ở cuối vòng lặp) thu được giá trị cuối cùng của "i", là giá trị cuối cùng trong phạm vi mà bạn đang lặp lại.

giải pháp thay thế:

class C 
    (1..10).each {|i| define_method("a#{i}") { puts i } } 
end 
3
>> class Pat 
.. (37..47). each do |i| 
..  define_method("a#{i}".to_sym) do 
..   puts i 
..  end 
..  end 
.. end #=> 37..47 
>> Pat.new.a40 #=> nil 
40 
>> Pat.new.a50 
NoMethodError: undefined method `a50' for #<Pat:0x00000100b39bc8> 

Edit: xin lỗi tôi không có thời gian cho một lời giải thích hợp lý, nhưng việc tìm kiếm nhanh chóng đưa ra một bài viết trên blog, nơi bạn sẽ có thể để có được những ý chính của nó: http://paulphilippov.com/articles/enumerableeach_vs_for_loops_in_ruby

2

Mặc dù câu trả lời @ RyanLeCompte là tốt hơn và sạch hơn (và đủ mô tả nguyên nhân của vấn đề), đây là một giải pháp thay thế, thời sau cách vấn đề này thường được tránh trong JavaScript:

class Foo 
    for i in 1..9 do 
    define_method "a#{i}", &(lambda{|x| lambda{puts x}})[i] 
    end 
end 
Foo.new.a1 
#=> 1 
Foo.new.a9 
#=> 9 

Không chấp nhận câu trả lời này, nhưng bỏ phiếu nếu bạn giúp bạn lên cấp lập trình meta. :)

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