Ruby: разница между объявлением переменной до и после цикла while?

#ruby #object #undefined

#ruby #объект #не определено

Вопрос:

Я работал над определенной проблемой, когда заметил, что все сбило с толку то, что я объявил переменную вне циклов while. Рассматриваемая переменная имеет значение sub_string = 1 . Похоже, что я должен объявить его после первого цикла while, прямо перед тем, как он фактически вступит в игру во втором цикле while. Объявляя ее раньше, цикл каким-то образом может распознавать только палиндромы, которые начинаются со строки [0] и, тем не менее, могут быть любой длины. На всю жизнь я не уверен, почему он ведет себя таким образом, поскольку я объявляю длину фрагмента (а не начальную позицию).

Простите меня, если я здесь упускаю что-то невероятно простое, поскольку я довольно новичок в программировании в целом.

Вот код, о котором идет речь (опущено определение палиндрома? метод проверки).

 def longest_palindrome(string)
  idx = 0
  longest = nil
  #substring_string = 1  ; declaring it early seems to cause weird issues to show up
  while idx < string.length
    substring_length = 1 #I have to declare the substring_length here

    while (idx   substring_length) <= string.length
      substring = string.slice(idx, substring_length)
      if palindrome?(substring) amp;amp; (longest == nil || substring.length > longest.length)
    longest = substring
    print substring_length
  end

  substring_length  = 1
end

  idx  = 1
  end

  return longest
end
 

Ответ №1:

Сценарий 1: substring_length определен внутри цикла while

 def longest_palindrome(string)
  idx = 0
  longest = nil
  while idx < string.length
    substring_length = 1
    while (idx   substring_length) <= string.length
      # palindrome
      substring_length  = 1 
    end
    idx  = 1
  end
  longest
end
 
  • Когда этот метод вызывается для объекта, поток управления выполнением переходит к первому while циклу. while idx < string.length
  • Внутри этого цикла вы инициализируете substring_length 1
  • Затем код переходит во вложенный цикл while (idx substring_length) <= string.length
  • Внутри вложенного цикла вызывается метод palindrome, который затем substring_length увеличивается на 1. Этот код выполняется до тех пор, пока его условие не вернет false (idx substring_length) < string.length . Следствием этого является то, что после завершения этого внутреннего цикла substring_length ВСЕГДА будет значение больше 1
  • Как только этот внутренний цикл заканчивается, управление возвращается к внешнему while циклу. Теперь первая строка кода переназначается substring_length на 1 . По сути, независимо от значения substring_length в конце внутреннего цикла, как только поток управления возвращается во внешний цикл, это значение отбрасывается, поскольку вы устанавливаете substring_length значение 1

Сценарий 2: substring_length определяется вне цикла while

 def longest_palindrome(string)
  idx = 0
  longest = nil
  substring_length = 1
  while idx < string.length
    while (idx   substring_length) <= string.length
      # palindrome
      substring_length  = 1 
    end
    idx  = 1
  end
  longest
end
 
  • Когда этот метод вызывается для объекта, он substring_length инициализируется значением 1, а затем поток управления выполнением переходит к первому while циклу. while idx < string.length
  • Если условие истинно, поток управления переходит ко второму циклу, inner циклу
  • Внутри внутреннего цикла вызывается метод palindrome, который затем substring_length увеличивается на 1. Этот код выполняется до тех пор, пока его условие не вернет false (idx substring_length) < string.length . Как и в сценарии 1, из этого следует, что после завершения этого внутреннего цикла substring_length ВСЕГДА будет значение больше 1
  • Как только этот внутренний цикл заканчивается, управление возвращается к внешнему while циклу. На этот раз нет инструкции инициализации, поэтому значение substring_length в конце внутреннего цикла — это то же самое значение, которое используется, когда управление возвращается во внешний цикл.

Давайте попробуем использовать пример

Сценарий 1

 longest_palindrome('him')
idx = 0; substring_length = 1; string.length = 3
while (0 < 3) # the outer loop condition is true,
substring_length = 1

# while (idx   substring_length) < string.length
while (0   1) < 3 # inner loop condition is true
# run code block, increment substring_length by 1, substring_length is NOW 2

while (0   2) < 3 # inner loop condition is still true
# run code block, increment substring_length by 1, substring_length is NOW 3

while (0   3) < 3 # inner loop condition fails, substring_length = 3

# Go to line after end of inner loop
increase idx by 1 # idx = 1

# Go back to outer loop
set substring_length to 1 # substring_length is NO MORE 3

# while (idx   substring_length) < string.length
while (1   1) < 3 # run code block, increment substring_length by 1, substring_length is NOW 2
while (1   2) < 3 # condition fails
..... and so on
 

Сценарий 2

 longest_palindrome('him')
idx = 0; substring_length = 1; string.length = 3
while (0 < 3) # the outer loop condition is true,

# while (idx   substring_length) < string.length
while (0   1) < 3 # inner loop condition is true
# run code block, increment substring_length by 1, substring_length is NOW 2

while (0   2) < 3 # inner loop condition is still true
# run code block, increment substring_length by 1, substring_length is NOW 3

while (0   3) < 3 # inner loop condition fails, substring_length = 3

# Go to line after end of inner loop
increase idx by 1 # idx = 1

# Go back to outer loop. Remember substring_length =3

# while (idx   substring_length) < string.length
while (1   3) < 3 # condition is false. Inner loop is NOT EXECUTED

# Go to line after end of inner loop
increase idx by 1 # idx = 1

# Go back to outer loop while (idx < string.length)
while (1 < 3) # outer loop condition is true

# Go to inner loop while (idx   substring_length) < string.length
while (1   3) < 3 # Once again condition is false and inner loop is NOT EXECUTED

# Go to line after end of inner loop
increase idx by 1 # idx = 1
 

Как вы можете видеть в этом сценарии, внутренний цикл перестает выполняться, потому substring_length что ему не присваивается значение 1, и условие постоянно выполняется с ошибкой.

Комментарии:

1. Ага. Я думаю, мне придется несколько раз перечитать ваше объяснение, чтобы разобраться, но большое спасибо за ответ!

2. Эй, @Tony, я отредактировал свой ответ. Надеюсь, это даст вам лучшее понимание.

3. Ваше объяснение было замечательным с самого начала. Ваше форматирование сделало его очень удобным, чтобы увидеть, в чем ключевое различие между двумя рассматриваемыми сценариями. Мой комментарий оборвался, и я почему-то не уловил этого (и не похоже, что я могу редактировать комментарии). Спасибо за ваше время. Мне нужно будет поискать в Google, как вы смогли показать вывод каждого цикла таким образом (поскольку я все время использовал print как часть своего цикла для получения информации о том, что делал код).