Closures and Loops in Ruby

I'm new to Ruby, and some of the closure logic is confusing to me. Consider this code:

array = []
for i in (1..5)
  array << lambda {i}
end
array.map{|f| f.call} # => [5, 5, 5, 5, 5]

This makes sense to me because I am bound outside the loop, so the same variable is captured every trip through the loop. It also seems to me that using each block can fix this:

array = []
(1..5).each{|i|  array << lambda {i}}
array.map{|f| f.call} # => [1, 2, 3, 4, 5]

... because I am now declared separately for each time. But now I'm lost: why can't I fix this by introducing an intermediate variable?

array = []
for i in 1..5
  j = i
  array << lambda {j}
end
array.map{|f| f.call} # => [5, 5, 5, 5, 5]

Since j is new every time, through a loop, I think that on each pass another variable will be written. For example, this is definitely how C # works, and how - I think - Lisp behaves with let. But there is not much in Ruby. What is really going on?

: . ; , j . ?

: , ; , :

for i in 1..5
  puts j if i > 1 #undefined local variable or method `j' for main:Object (NameError)
  j = i
end
+5
2

, . , , for Ruby, .

, , , for Ruby, , : -)

, , , 1 2009 Ruby IPA ( Ruby ISO):

§11.4.1.2.3 for

  • for in do-clause end
  • |

.

A :

  • . O - .
  • E - -- primary-expression [no line-terminator here] .each do | block-formal-argument-list | block-body end, O, --- for, - - do-clause.

    E, c §11.2.2.

  • for- .

, ,

for for_variable in expression
  do_clause
end

O = expression
O.each do |for_variable|
  do_clause
end

, :

for i in 1..5
  puts j if i > 1 #undefined local variable or method `j' (NameError)
  j = i
end

(1..5).each do |i|
  puts j if i > 1 #no excpetion here, works just fine ??!!??
  j = i
end

! - ! " c §11.2.2". ! , ?

  • ⟦local-variable-bindings.

, b

  • E b.

.

, , for , , . IOW: , .

, , , , .

+9

Ruby ? 1.8 , j ( 5) for.

+1

All Articles