Ruby забывает локальные переменные во время некоторое время цикла?

Это - часть стандарта языка C++. Неявный возврат 0 сгенерирован для Вас, если нет никакого явного оператора возврата в основном.

15
задан monojohnny 2 November 2009 в 15:03
поделиться

4 ответа

I think this is because message is defined inside the loop. At the end of the loop iteration "message" goes out of scope. Defining "message" outside of the loop stops the variable from going out of scope at the end of each loop iteration. So I think you have the right answer.

You could output the value of message at the beginning of each loop iteration to test whether my suggestion is correct.

8
ответ дан 1 December 2019 в 00:14
поделиться

From the Ruby Programming Language:

alt text http://bks0.books.google.com/books?id=jcUbTcr5XWwC&printsec=frontcover&img=1&zoom=5&sig=ACfU3U1rnYKha_p7vEkpPm1Ow3o9RAM0nQ

Blocks and Variable Scope

Blocks define a new variable scope: variables created within a block exist only within that block and are undefined outside of the block. Be cautious, however; the local variables in a method are available to any blocks within that method. So if a block assigns a value to a variable that is already defined outside of the block, this does not create a new block-local variable but instead assigns a new value to the already-existing variable. Sometimes, this is exactly the behavior we want:

total = 0   
data.each {|x| total += x }  # Sum the elements of the data array
puts total                   # Print out that sum

Sometimes, however, we do not want to alter variables in the enclosing scope, but we do so inadvertently. This problem is a particular concern for block parameters in Ruby 1.8. In Ruby 1.8, if a block parameter shares the name of an existing variable, then invocations of the block simply assign a value to that existing variable rather than creating a new block-local variable. The following code, for example, is problematic because it uses the same identifier i as the block parameter for two nested blocks:

1.upto(10) do |i|         # 10 rows
  1.upto(10) do |i|       # Each has 10 columns
    print "#{i} "         # Print column number
  end
  print " ==> Row #{i}\n" # Try to print row number, but get column number
end

Ruby 1.9 is different: block parameters are always local to their block, and invocations of the block never assign values to existing variables. If Ruby 1.9 is invoked with the -w flag, it will warn you if a block parameter has the same name as an existing variable. This helps you avoid writing code that runs differently in 1.8 and 1.9.

Ruby 1.9 is different in another important way, too. Block syntax has been extended to allow you to declare block-local variables that are guaranteed to be local, even if a variable by the same name already exists in the enclosing scope. To do this, follow the list of block parameters with a semicolon and a comma-separated list of block local variables. Here is an example:

x = y = 0            # local variables
1.upto(4) do |x;y|   # x and y are local to block
                     # x and y "shadow" the outer variables
  y = x + 1          # Use y as a scratch variable
  puts y*y           # Prints 4, 9, 16, 25
end
[x,y]                # => [0,0]: block does not alter these

In this code, x is a block parameter: it gets a value when the block is invoked with yield. y is a block-local variable. It does not receive any value from a yield invocation, but it has the value nil until the block actually assigns some other value to it. The point of declaring these block-local variables is to guarantee that you will not inadvertently clobber the value of some existing variable. (This might happen if a block is cut-and-pasted from one method to another, for example.) If you invoke Ruby 1.9 with the -w option, it will warn you if a block-local variable shadows an existing variable.

Blocks can have more than one parameter and more than one local variable, of course. Here is a block with two parameters and three local variables:

hash.each {|key,value; i,j,k| ... }
29
ответ дан 1 December 2019 в 00:14
поделиться

Не знаю, почему вы удивлены: в строке 5 (при условии, что строки message = nil там нет), вы потенциально можете использовать переменную, которая переводчик никогда раньше не слышал. Интерпретатор говорит: «Что такое сообщение ? Это не метод, который я знаю, это не переменная, которую я знаю, это не ключевое слово ...», и затем вы получаете сообщение об ошибке.

Вот более простой пример чтобы показать вам, что я имею в виду:

while line = gets do
  if line =~ /./ then
    puts message # How could this work?
    message = line
  end
end

Что дает:

telemachus ~ $ ruby test.rb < huh 
test.rb:3:in `<main>': undefined local variable or method `message' for main:Object (NameError)

Кроме того, если вы хотите подготовить путь для сообщения , я бы инициализировал его как message = '' , так что это строка (а не nil ). В противном случае, если ваша первая строка не соответствует привет, вы закончите попыткой добавить строку к nil - что приведет к этой ошибке:

telemachus ~ $ ruby test.rb < huh 
test.rb:4:in `<main>': undefined method `<<' for nil:NilClass (NoMethodError)
2
ответ дан 1 December 2019 в 00:14
поделиться

Why do you think this is a bug? The interpreter is telling you that message may be undefined when that particular piece of code executes.

2
ответ дан 1 December 2019 в 00:14
поделиться