Ruby: как инициализировать значение переменной блока - PullRequest
0 голосов
/ 19 сентября 2018

Я изучаю Ruby и набрал фрагмент кода, чтобы поэкспериментировать с переменными в области блока:

x = 10
3.times do |i; x|
  x = x + 1
  puts("inside block is #{x}")
end
puts("outside block is #{x}")

Я бы ожидал, что блочная переменная x автоматически захватит значение глобальной переменной x, изатем x внутри блока будет каждый раз равным 11, а x вне блока, который должен быть защищен, и остается на 10. Это «экранирующее» действие - это то, что описано во многих учебных пособиях по Ruby, которые можно найти в Интернете.

Новместо этого скрипт завершается ошибкой, сообщая мне, что x равен nil и что у него нет функции +.Другими словами, переменная блока x не была инициализирована значением.

Код точный , приведенный выше, находится в файле с именем delete_me.rb и работает с: ruby delete_me.rb

Когда я запускаю скрипт, я получаю следующую ошибку:

delete_me.rb:3:in `block in <main>': undefined method `+' for nil:NilClass (NoMethodError)
    from delete_me.rb:2:in `times'
    from delete_me.rb:2:in `<main>'

Как мне инициализировать значение переменной блока в Ruby?

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

Это связано с тем, что блоки ruby ​​не создают новую область видимости, НО они создают переменные в своей таблице поиска.

Ваш блок будет иметь доступ к глобальной переменной x, НО вы передаете x в качестве аргумента дляблок.Когда время повторяется, оно передает i, а x устанавливается в nil, потому что ему не передается переменная.Таким образом, в вашем блоке у вас есть новый x, который имеет значение nil на каждой итерации.Если вы передадите любую другую именованную переменную, она будет работать.

x = 10
3.times do |i; y|
  x = x + 1
  puts("x block is #{x}")
end
puts("outside block is #{x}")

Или даже лучше, не определяйте ее с другим аргументом, если вы не хотите переопределять глобальные переменные

x = 10
3.times do |i|
  x = x + 1
  puts("x block is #{x}")
end
puts("outside block is #{x}")
0 голосов
/ 19 сентября 2018

Я ожидал бы, что переменная блока x автоматически захватит значение глобальной переменной x,

Это не то, как работает Ruby, и нет никаких оснований ожидать, что он будет себя вестисюда.Внутренняя переменная никогда не берет своего значения из переменной, которую она затеняет, на любом языке, который я знаю.Это был бы ужасно разработанный язык, где несвязанный внешний контекст мог быть изменен или введен, что нарушает внутреннюю сферу совершенно непредвиденными способами.Цель scope состоит в том, чтобы предотвратить подобные вещи.

x - это nil, потому что это недавно введенная переменная, которую вы не сделалиприсвоить значение.

Как инициализировать значение переменной блока в Ruby?

Можно проверить, является ли оно nil, а затем назначитьзначение для него:

x = 10
3.times do |i; x|
  x ||= 0
  x = x + 1
  puts("inside block is #{x}")
end
puts("outside block is #{x}")

Обратите внимание, что этот цикл печатает "inside block is 1" три раза.Вы делаете новый x и устанавливаете его в 0 каждый раз, когда блок вызывается.Если вы хотите накапливать состояние во время итерации, это неправильный путь.Вы либо хотите , а не затенять внешнее x, либо использовать другой перечисляемый метод, например inject или each.with_object.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...