代码之家  ›  专栏  ›  技术社区  ›  user24359

Ruby中的闭包和for循环

  •  5
  • user24359  · 技术社区  · 14 年前

    我对Ruby有点陌生,一些闭包逻辑让我很困惑。考虑此代码:

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

    这对我来说是有意义的,因为我被绑定在循环之外,所以通过循环的每次旅行都会捕获相同的变量。对我来说,使用每个块也可以解决这个问题:

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

    …因为我现在每次都被单独宣布。但是现在我迷路了:为什么我不能通过引入一个中间变量来修正它呢?

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

    因为J每次在循环中都是新的,所以我想每次传递都会捕获不同的变量。例如,这就是C的工作方式,我认为Lisp是如何使用let的。但在红宝石里就没那么多了。到底发生了什么?

    编辑:参见答案中的注释;问题似乎是J仍然在循环之外的范围内。循环中的作用域是如何工作的?

    编辑:我想我还是不明白;如果循环不创建新的作用域,为什么:

    for i in 1..5
      puts j if i > 1 #undefined local variable or method `j' for main:Object (NameError)
      j = i
    end
    
    2 回复  |  直到 13 年前
        1
  •  9
  •   Jörg W Mittag    14 年前

    好吧,这越来越荒谬了。每次我试图回答一个关于如何 for 循环在Ruby中工作,我弄错了。

    当然,这是因为我不使用 对于 Ruby中的循环,其他任何人都没有,所以这对我来说真的不重要:—)

    不管怎样,为了彻底解决这件事,我直接去了 the ultimate source ,2009年12月1日,IPA Ruby语言规范初稿(注定成为ISO Ruby语言规范):

    _11.4.1.2.3 对于 表达

    句法

    • 为了表达 渐次 对于 对于变量 在里面 表达 执行子句 结束
    • 对于变量 渐次 左手边 γ 多左侧

    这个 表达 A的 为了表达 不得为 跳转表达式 .

    语义

    为了表达 评估如下:

    1. 评价 表达 . 让 O 是结果值。
    2. E 成为 主方法调用 形式的 主表达式 [此处没有行终止符] 每个做什么? 块形式参数列表 γ 块体 结束 ,其中 主表达式 o ,the 块形式参数列表 对于变量 , the 块体 复合语句 执行子句 .

      评价 e ,但跳过第11.2.2节的步骤c。

    3. 的值 为了表达 是调用的结果值。

    好吧,所以基本上这意味着

    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
    

    啊哈!但我们忘了什么!这里有一个不祥的“跳过第11.2.2节的步骤c”。事情!那么,它说什么?

    • 将一组空的局部变量绑定推送到____§局部变量绑定上。

    注意步骤b

    • 将执行上下文设置为 e b .

    跳过。

    据我所知 对于 循环获取自己的执行上下文,该上下文以当前执行上下文的副本开始,但它 获取自己的局部变量绑定集。iow:它有自己的动态执行上下文,但没有自己的词汇范围。

    我必须承认,我仍然不确定我是否完全理解它,但它不会比这更精确。

        2
  •  1
  •   x1a4    14 年前

    你用的是什么版本的Ruby?1.8没有局部变量的块范围,因此即使在 for .