2011-01-18 2 views
1
jobs.each do | job | 
    msg job.name do 
    break if stop_all_jobs? 
    job.run! 
    end 
end 

def msg(msg, &block) 
    puts 'START ' + msg 
    yield 
    puts 'END ' + msg 
end 

В приведенном выше примере break не выходит из цикла, как ожидалось. Он вырывается из блока кода msg.Как вырвать цикл из кода в (выход)?

Это кажется немного странным, но я полагаю, что он основан на контексте, который сказал, как я вырваться из цикла из кода, который находится внутри блока кода ed?

+0

Чтобы быть понятным, вы хотите «вернуть» из 'msg', чтобы' 'END" 'никогда не печатался? Или вы пытаетесь просто «job.run!» Никогда не вызывать, но продолжаете «msg»? – Phrogz

ответ

2

Один из способов - использовать throw/catch. Нет, не исключение, Ruby имеет отдельную функцию управления потоком, которая немного похожа на исключения, без всех накладных расходов (хотя я должен признать, что я не уверен, что нет любых накладных расходов при ее использовании):

catch :stop_all_jobs do 
    msg job.name do 
    throw :stop_all_jobs if stop_all_jobs? 
    job.run! 
    end 
end 

Вы можете даже передать значение в качестве второго аргумента throw который будет являться результатом catch блока.

Потенциально более читаемым решением было бы, конечно же, упаковать код в методе и использовать return вместо break. Но это было бы не так весело.

+0

throw/catch кажется немного похожим на goto, или это только я? – Kris

+0

Да. Это goto с другим именем и возвращаемым значением :) – Theo

+0

Когда Ruby сталкивается с броском, он застегивает резервную копию стека вызовов, ища блок catch с соответствующим символом. Когда он находит это, Ruby разворачивает стек до этой точки и завершает блок. Cite: http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_exceptions.html – Kris

-2

Использовать next вместо break.

Смежные вопросы