В Ruby, что делает задание верхнего уровня? - PullRequest
0 голосов
/ 16 сентября 2018

У меня есть следующий код на верхнем уровне файла .rb:

class Times
    def initialize(n)
        @n = n               
    end
    def each()        
        (1..@n).each {yield}
    end
end
three_times = Times.new(3)

def f()
    Times.new(3).each {puts 'Test'}
end
f()

Это работает и печатает «Test» три раза, как и ожидалось.Однако, если я заменю Times.new(3) в f на three_times, то есть three_times.each {puts 'Test'}, я получу ошибку:

`f': undefined local variable or method `three_times' for main:Object (NameError)

Почему это не работает?Почему Times доступен из f, а не three_times?

В целом, что именно делает задание на верхнем уровне (например, three_times = Times.new(3))?

Ответы [ 4 ]

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

Почему это не работает?Почему Times доступен из f, но не three_times?

Переменные, имена которых начинаются со строчной буквы, локальные переменные .Локальные переменные являются локальными для области, в которой они определены (поэтому они называются локальные переменные.)

Переменные, имена которых начинаются с заглавной буквы, являются константами .Константы ищутся сначала в области констант по умолчанию, затем лексически наружу, затем динамически вверх по наследованию.

В целом, что именно делает назначение на верхнем уровне (например, three_times = Times.new(3))?

Ничего особенного.Он делает то же самое, что и назначение в другом месте.В данном случае это:

  1. Разыменовывает переменную (константу) Times, давайте назовем этот объект o1 .
  2. Оценивает литеральное целочисленное выражение 3, давайте назовем получившийся объект o2 .
  3. Посылает сообщение new в o1 , передавая o2 в качестве аргумента.Давайте назовем ответ на это сообщение, отправив o3 .
  4. Связывает o3 с локальной переменной с именем three_times.

As youможно увидеть, что там нет ничего, что было бы как-то специфично для области видимости скрипта или верхнего уровня.

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

Потому что

  • three_times является локальной переменной
  • локальные переменные доступны только внутри определенной области видимости
  • def в ruby ​​создает новую область видимости

Поэтому, когда вызывается f, он не видит или не имеет доступа к three_times

Чтобы получить доступ к Three_times, измените его на глобальную переменную $three_times или переменную экземпляра @three_times

Причина, по которой вы можете ссылаться на класс Times, заключается в том, что он является константой, а ruby ​​проходит отдельный процесс поиска констант.


Ошибка с def

Вы также можете получить доступ к локальной переменной, используя блок для определения вашего метода, который обходит проблему с целыми областями видимости. Я делаю это иногда, когда пишу грабли, но редко делаю это вне скриптов.

three_times = Times.new(3)
define_method :foo do
  three_times.each { puts 'Tests'}
end
foo
0 голосов
/ 16 сентября 2018

Ваш код у меня работает, ошибок нет.Вы можете позвонить f() успешно

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

Это потому, что он ищет локальную переменную с именем "three_times".Если вы хотите, чтобы «three_times» был «top-level» или «global», добавьте к имени переменной $ так, чтобы оно равнялось «$ three_times».

...