Ruby循环局部变量和不可变性

时间:2017-02-02 10:28:01

标签: ruby functional-programming

我有以下代码:

# Assuming each element in foo is an array.
foo.each do |bar|
  zaz = bar.first
  # Other code using zaz, but not modifying it.
end

在此循环内的每次迭代中是否会修改zaz局部变量,使其变为可变?我不确定Ruby的行为。

2 个答案:

答案 0 :(得分:4)

这取决于循环之前的代码,真的。

如果那是 all 代码,那么zaz是一个块本地变量,每个都会创建一个 new zaz变量评估循环体的时间。

但是,如果周围范围中存在zaz局部变量,则zaz是块中的自由变量,并且由于块范围嵌套在其周围范围内,因此现有zaz每次对块进行求值时,块内外的变量将反复重新分配。

您可以确保zaz始终被视为块局部变量,并且永远不会在周围范围内查找,方法是在块的参数列表中将其明确声明为块局部变量:

foo.each do |bar; zaz|
  zaz = bar.first
end

但请注意,您的代码只有正确 IFF 您的代码不纯净且可变:

  1. 您分配给zaz但从未在块内实际使用它。因此,唯一有意义的方法是,zaz是外部作用域中的局部变量,并且您正在分配它。虽然在这种情况下,您的整个循环只相当于zaz = foo.last.first
  2. each仅针对其副作用评估该块。没有副作用,each完全没有意义,所以你使用each的事实暗示你有副作用。
  3. 注意术语"不可变"没有额外资格通常是指价值观。在谈论"不可变变量"时,我们通常会说"不可变变量"显式地,明确我们只讨论变量是否可以重新绑定,而不是变异对象状态。或者,可以说"常数",这是"不可变变量"的技术术语。 ......虽然这个术语在Ruby中已经具有特定含义。

答案 1 :(得分:1)

each循环经常改变对象。每个人都必须做点什么。 因为each没有返回任何有用的东西 - 它返回数组本身,如果它在某个地方发送每个元素,它就不会改变对象,就像在屏幕上打印一样。

foo.each do |bar|
  # do something with element like
  # print it, change it, save it
end

功能变化是地图

foo.map { |bar| bar.something }

它返回新数组,它是以不可变方式处理的原始数组。显然你必须小心使用不可变方法。这不是一成不变的:

foo.map { |bar| bar.something! } 

这里something!会对数组元素造成破坏性影响。 但是我从来没有见过map那样的用法。使用each来破坏性的东西。