2016-10-30 3 views
2

(1)Удивительным Рубин обзорное с в то время как петля

a = [1, 2] 
while b = a.pop do puts b end 

выходы

2 
1 

(2)

a = [1, 2] 
puts b while b = a.pop 

приводит к ошибке

undefined local variable or method `b' 

(3)

b = nil 
a = [1, 2] 
puts b while b = a.pop 

выходы

2 
1 

Что происходит? Почему область b отличается от №2, чем любая другая?

$ ruby --version 
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux] 

EDIT: Первоначально я перечислил поведение IRB как разные. Это не так; Я работал в «грязной» сессии.

+1

хотя бы попробовать рубин, который менее древний :) –

+0

@SergioTulentsev, справедливая точка. Я использую последнее в репозиториях Ubuntu 14.04 LTS :) –

+2

Когда вы читаете свой пример # 2 по строкам слева направо, '' '' 'определяется в конце инструкции' puts'? Я не удивлен, не так ли? Еще один более короткий пример, который не подходит по той же причине: 'p a if a' – spickermann

ответ

0

Оператор puts выполняется до того, как изначально определена переменная 'b', что приводит к ошибке.

Как аналогичный пример, но с до-заявления, не рассмотрим следующий код:

a = [1, 2] 
begin 
    puts "in the block" 
end until b = a.pop 

можно ожидать б быть определена в блоке?

Технически единственным отличием является то, что до тех пор, пока не будет установлено истинное значение возврата, пока оно будет продолжаться до тех пор, пока a.pop вернет истинное значение.

Дело в обоих случаях является то, что б не является в рамках до присвоения произошло. Сразу после назначения, например, когда цикл возвращается, b появляется в текущей области. Это называется лексическим охватом, и как работает рубин для локальных переменных, подобных этому.

Я нашел this article, чтобы быть полезной для понимания области действия в рубине.

Update 1: В предыдущей версии моего ответа я написал, что это не сравнимо с если. Хотя это все еще так, это не имеет никакого отношения к вопросу, который является простой проблемой с областью.

Обновление 2: Добавлена ​​ссылка на более подробные пояснения относительно области видимости в рубине.

Обновление 3: Убрано первое предложение, поскольку это было неправильно.

+0

Ну, это не работает с 'if'. –

+0

Ха, вы правы. Я обманул себя, когда я (иронически) намеревался доказать то же самое утверждение, что это происходит с if. Ответ обновлен. –

+0

«Вторая форма должна запускать блок кода хотя бы один раз, прежде чем проверять условие». - Это ложь. Проверьте сами: 'a = []; помещает «x», пока a.pop' ничего не отображает; 'a = []; begin ставит конец «x», в то время как a.pop' отображает «x». Это две разные конструкции с различной семантикой. Помимо первого абзаца, остальная часть ответа хороша. – Amadan

-1
a = [1, 2] 
while b = a.pop do puts b end 

такое же как

a = [1, 2] 
b = a.pop 
puts b 
b = a.pop 
puts b 

(2)

a = [1, 2] 
puts b while b = a.pop 

такой же, как это

a = [1, 2] 
puts b 
b = a.pop 
puts b 
b = a.pop 
puts b 

Когда б передается в помещает в первый раз, она не но были инициализированы. поэтому сообщение об ошибке

(3) b инициализируется нулем. даже нулевой является объектом рубина

b = nil 
a = [1, 2] 
puts b while b = a.pop 
+1

Это неправда; 'statement while condition' выполняет' statement' столько же раз, сколько 'while condition; заявление; end'. (2) не запускает 'puts' больше раз, чем (1). – Amadan

0

Переменными объявляются для их охвата лексического анализатора, который является линейным. В while b = a.pop do puts b end назначение (b = a.pop) видно синтаксическому анализатору перед использованием (puts b). Во втором примере puts b while b = a.pop использование видно, когда определение все еще неизвестно, что приводит к ошибке.