Variable scope in Ruby

Consider the following two snippets of ruby ​​code.

puts "One" if false d = 1 end puts "Two" puts d puts "Three" 

The following is printed

 One Two Three 

Now consider the following

 [].each do |i| flag = false end puts "Two" puts flag puts "Three" 

This gives the following

 Two '<main>': undefined local variable or method 'flag' for main:Object (NameError) 

Why is a space printed in the first case, and an error occurs in the second case?

thanks

+5
source share
2 answers

The difference is that the if block if not actually a separate area, as in other languages ​​such as Java. Variables declared in an if block have the same scope as the environment. Now in your case, this if block will not actually be executed, so usually you expect d be undefined (which will lead to the same error as in the second example). But ruby ​​is a bit of “smrt” because the interpreter will set the variable with this label the moment it sees it, regardless of whether it actually runs, because it essentially doesn’t know yet, really whether this branch will be executed. This is explained in "Ruby Programming Language" by David Flanagan and Yukihiro Matsumoto (cannot copy paste text by adding a screenshot instead): enter image description here

In the case of the .each loop, what the do...end you wrote is actually block , and it has its own local scope. In other words, variables declared inside a block are local to that block only.

However, the blocks “inherit” the area of ​​the environment in which they are declared, so you can make the flag declaration outside the .each iteration .each , and then the block will be able to access it and set its value. Please note that in the example you provided, this will not happen because you are trying to iterate over an empty array, but at least you will not get the error anymore.

Some additional reading:

+5
source

In Ruby, when you assign a variable (in your case, it is d ) anywhere in the If-statement False branch, it declares this variable if the d= method is not defined. Basically b = bla-bla-bla in False-branch does this: b = nil .

When you use a block in an empty array, nothing happens. And if the array is not empty, the variable is still local to the current iteration of the block, unless the outer region of the block is defined, for example:

 [1,2,3,4].each do |i| a=i end puts a 

NameError: undefined local variable or `a 'method for main: Object

 a=1 [1,2,3,4].each do |i| a=i end puts a 

4

Also, you have the option to use a as local inside the block, if it was previously defined:

 a=1 [1,2,3,4].each do |i; a| a=i end puts a 

1

+2
source

Source: https://habr.com/ru/post/1236727/


All Articles