简体   繁体   中英

Ruby loop local variables and inmutability

I have the following code:

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

Will zaz local variable be modified on each iteration inside this loop, making it mutable? I am not sure about the behavior of Ruby here.

It depends on the code before the loop, really.

If that is all the code, then zaz is a block-local variable, and a new zaz variable will be created every time the loop body is evaluated.

If, however, there is a zaz local variable in the surrounding scope, then zaz is a free variable in the block, and since block scopes nest in their surrounding scope, the existing zaz variable outside the block will be re-assigned over and over again, every time the block is evaluated.

You can ensure that zaz is always treated as a block-local variable and never looked up in the surrounding scope, by explicitly declaring it as a block-local variable in the block's parameter list:

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

Note, however, that your code only makes sense IFF your code is impure and mutable:

  1. You assign to zaz but never actually use it inside the block. So, the only way that this makes sense at all is if zaz is a local variable in the outer scope and you are assigning it. Although in that case, your entire loop is just equivalent to zaz = foo.last.first .
  2. each evaluates the block only for its side-effects. Without side-effects, each makes no sense at all, so the fact that you are using each implies that you have side-effects.

Note that the term "immutable" without additional qualification usually refers to values. When talking about "immutable variables", we usually say "immutable variable" explicitly, to make clear that we are only talking about whether or not a variable can be re-bound, not about mutating object state. Or, one could just say "constant", which is the technical term for "immutable variable" … although that term already has a specific meaning in Ruby.

each loops often mutate the object. Each has to do something. Because each doesn't return anything useful - it returns the array itself, It won't mutate the object if it sends every element somewhere, like to be printed on screen.

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

Functional alterantive is map

foo.map { |bar| bar.something }

It returns new array which is original array processed in immutable way. Obviously you have to be careful to use immutable methods. This would not be immutable:

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

Here something! does something destructive to the element of array. However I have never seen map used like that. Use each for something destructive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM