Как повредить внешний цикл в Ruby?

Я раньше работал с кем-то, кто сказал, "если компилятор к немому для выяснения то, что Вы пытаетесь сделать и не можете оптимизировать его, Ваш компилятор повреждается, и пора получить новое". Я уверен, что существуют пограничные случаи, когда блок разобьет Ваш код C, но если Вы часто используете ассемблер "победить" по Вашему компилятору, Ваш компилятор арестован.

То же может быть сказано для записи "оптимизированного" SQL, который пытается принудить планировщика запроса в выполнение вещей. Если Вы перестраиваете запросы заставлять планировщика делать то, что Вы хотите, Ваш планировщик запроса арестован - получают новый.

54
задан ire_and_curses 29 August 2009 в 08:11
поделиться

5 ответов

То, что вам нужно, это нелокальный поток управления, для чего у Ruby есть несколько вариантов:

  • Продолжение,
  • Исключения и
  • throw / ] catch

Продолжения

Плюсы:

  • Продолжения являются стандартным механизмом для нелокального потока управления. Фактически, вы можете построить любой нелокальный поток управления (подпрограммы, процедуры, функции, методы, сопрограммы, конечные автоматы, генераторы, условия, исключения) поверх них: они в значительной степени лучше близнец GOTO .

Минусы:

  • Продолжения не являются обязательной частью спецификации языка Ruby, что означает, что некоторые реализации (XRuby, JRuby, Ruby.NET, IronRuby) не реализуют их. Так что на них нельзя положиться.

Исключения

Плюсы:

  • Есть статья, которая математически доказывает, что исключения могут быть более мощными, чем продолжения. IOW: они могут делать все, что могут делать продолжения, и даже больше, поэтому вы можете использовать их в качестве замены продолжений.
  • Исключения доступны повсеместно.

Минусы:

  • Их называют «исключениями», что заставляет людей думаю, что они предназначены «только для исключительных обстоятельств». Это означает три вещи: кто-то, читающий ваш код, может его не понять, реализация может быть не оптимизирована для него (и, да, исключения ужасно медленны почти в любой реализации Ruby) и, что хуже всего, вы будете надоедает всем этим людям, бессмысленно бормочущим «исключения только для исключительных обстоятельств», как только они взглянут на ваш код. (Конечно, они победили '' Я даже не пытаюсь понять, что вы делаете.)

throw / catch

Это (примерно) то, как это будет выглядеть:

catch :aaa do
  stuff.each do |otherstuff|
    foo.each do |bar|
      throw :aaa if somethingbad
    end
  end
end

Плюсы:

  • То же, что и исключения.
  • В Ruby 1.9 использование исключений для потока управления фактически является частью спецификации языка ! Циклы, перечислители, итераторы и тому подобное - все используют исключение StopIteration для завершения.

Минусы:

  • Сообщество Ruby ненавидит их даже больше, чем использование исключений для потока управления.
36
ответ дан 7 November 2019 в 07:37
поделиться

Рассмотрим throw / catch . Обычно внешний цикл в приведенном ниже коде выполняется пять раз, но с помощью throw вы можете изменить его на все, что захотите, сломав его в процессе. Рассмотрим этот совершенно допустимый рубиновый код:

catch (:done) do
  5.times { |i|
    5.times { |j|
      puts "#{i} #{j}"
      throw :done if i + j > 5
    }
  }
end
106
ответ дан 7 November 2019 в 07:37
поделиться

Нет, нет.

Возможны следующие варианты:

  • поместить цикл в метод и использовать return для выхода из внешнего цикла
  • установить или вернуть флаг из внутреннего цикла, а затем проверьте этот флаг во внешнем цикле и прервите его, когда флаг установлен (что довольно громоздко)
  • используйте throw / catch для выхода из цикла
30
ответ дан 7 November 2019 в 07:37
поделиться

Я знаю, что пожалею об этом утром, но простое использование цикла while может помочь.

x=0
until x==10
  x+=1
  y=0
  until y==10
    y+=1
    if y==5 && x==3
      x,y=10,10
    end
  end
  break if x==10
  puts x
end

if y == 5 && x == 3 - это только пример выражение становится правдой.

0
ответ дан 7 November 2019 в 07:37
поделиться

Может, это то, что вам нужно? (не проверено)

stuff.find do |otherstuff|
  foo.find do
    somethingbad() && AAA
  end
end

Метод find продолжает цикл до тех пор, пока блок не вернет ненулевое значение или не будет достигнут конец списка.

2
ответ дан 7 November 2019 в 07:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: