12

初学者 Ruby 问题。更改此代码的最简单方法是什么,但保持块完全不变,从而消除副作用?

x = lambda { |v| x = 2 ; v}
x.call(3)
#=> 3
x
#=> 2

这是我可以设法说明我的问题的最简单的示例,因此“删除分配”或“不要将 Proc 分配给 x”不是我想要的。

我想在 Proc(或 lambda)中设置可以在不影响原始封闭范围的情况下分配的局部变量。我可以动态创建一个类或模块来包装块,但这对于这样一个基本的东西来说似乎有点过分了。

相当于我正在尝试做的Python:

def x(v):
  x = 2  # this is a local variable, what a concept
  return v
4

2 回答 2

28

有时这是期望的行为:

total = 0
(1..10).each{|x| total += x}
puts total

但有时这是偶然的,您不想弄乱恰好具有相同名称的外部变量。在这种情况下,使用分号和块局部变量列表跟随参数列表:

x = lambda{|v; x| x = 2; v}
p x.call(3) #3
p x #<Proc:0x83f7570@test1.rb:2 (lambda)>
于 2013-05-22T20:07:22.800 回答
6

这样做的原因是 lambda 绑定到它的定义范围(而不是它的调用范围),并且是一个完整的闭包,其中包括局部变量x。您在这里真正想要的是一个未绑定的过程,可以在没有任何特定绑定的情况下传递和调用。按照设计,这根本不是 Ruby 很容易做到的(使用 eval 是可能的,但这不是一个块,而更像是一个字符串语句)。Procs、lambdas 和块都绑定到它们的定义范围。词法范围只建立在类、模块和方法上;不在块/procs/lambdas/其他任何东西上。

值得注意的是,Python 甚至一开始就不允许在 lambda 中赋值。

于 2013-05-22T19:43:54.760 回答