Локальные переменные имеют имя, начинающееся с символа нижнего подчёркивания или буквы в нижнем регистре. Локальные переменные работают не так, как глобальные переменные или переменные экземпляров классов, которые имеют значение nil до инициализации:
- ruby> $foo
- nil
- ruby> @foo
- nil
- ruby> foo
- ERR: (eval):1: undefined local variable or method `foo' for main(Object)
При первом назначении вы создаёте локальную переменную выполняя её объявление. Если обратиться к неинициализированной локальной переменной, то интерпретатор Ruby подумает об этом, как о попытке вызвать метод с этим именем; соответственно вы увидите сообщение об ошибке.
Как правило локальная переменная размещается в одном из следующих местоположений в коде:
- proc{...}
- loop{...}
- def ... end
- class ... end
- module ... end
- в теле программы (в том случае, если не подходит всё выше перечисленное)
В следующем примере defined? является оператором, который проверяет определён ли идентификатор. Он возвращает описание идентификатора, если он определён, или nil в противном случае. Как Вы видите, областью размещения bar является цикл loop ; когда мы выходим из цикла, тогда bar является неопределённым.
- ruby> foo = 44; print foo, "\n"; defined? foo
- 44
- "local-variable"
- ruby> loop{bar=45; print bar, "\n"; break}; defined? bar
- 45
- nil
Процедурные объекты, которые живут в той же разделяемой области независимо от локальных переменных, также относятся к той же области, что и переменные. Здесь, локальная переменная bar является разделяемой между main и процедурными объектами p1 и p2:
- ruby> bar=0
- 0
- ruby> p1 = proc{|n| bar=n}
- #<Proc:0x8deb0>
- ruby> p2 = proc{bar}
- #<Proc:0x8dce8>
- ruby> p1.call(5)
- 5
- ruby> bar
- 5
- ruby> p2.call
- 5
Заметьте, что bar=0 в самом начале не может быть опущено; Это назначение гарантирует, что область видимости bar будет включена в p1 и p2. В противном случае p1 и p2 будет иметь каждый свою собственную переменную bar . И вызывая, p2 мы получим ошибку "undefined local variable or method".
Мощь функционала процедурных объектов в их способности передаваться в качестве аргументов: разделяемые локальные переменные остаются рабочими, даже когда они передаются из изначальной области видимости.
- ruby> def box
- | contents = 15
- | get = proc{contents}
- | set = proc{|n| contents = n}
- | return get, set
- | end
- nil
- ruby> reader, writer = box
- [#<Proc:0x40170fc0>, #<Proc:0x40170fac>]
- ruby> reader.call
- 15
- ruby> writer.call(2)
- 2
- ruby> reader.call
- 2
Ruby является интеллектуальным относительно областей видимости. Очевидно, что в нашем примере переменная contents является разделяемой между reader и writer . Но мы можем также произвести множество пар reader-writer , используя box как определено выше; Каждая пара разделяет переменную contents , и пары не интерферируют друг с другом.
- ruby> reader_1, writer_1 = box
- [#<Proc:0x40172820>, #<Proc:0x4017280c>]
- ruby> reader_2, writer_2 = box
- [#<Proc:0x40172668>, #<Proc:0x40172654>]
- ruby> writer_1.call(99)
- 99
- ruby> reader_1.call
- 99
- ruby> reader_2.call
- 15