1 Вопрос: Как работает оператор повтора в Ruby?

вопрос создан в Wed, May 8, 2019 12:00 AM

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

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

Я пробовал много вещей: - Первый использовал ключевое слово «begin» в начале метода и «Повышение» в точке повтора, за которым следовало соответствующее «спасение»; повторить попытку; конец;'. -Последний использовал снаружи блок «begin /rescue», оборачивая вызов метода.

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

Есть несколько примеров:

Код в руководстве выглядит следующим образом:

def WHILE(cond)
  return if not cond
  yield
  retry
end
i=0; WHILE(i<3) {print i; i+=1}

Результат: 012 р>

Я пробовал следующее:

def WHILE(cond)
  begin
    return if not cond
    yield
    raise
  rescue
    retry
  end
end
i=0; WHILE(i<3) {print i; i+=1}

Результат: бесконечные числа

def WHILE(cond)
  return if not cond
  yield
end
i=0; begin; WHILE(i<3) {print i; i+=1}; raise; rescue; retry; end

Результат: 012 (плюс очевидный бесконечный цикл, ничего не печатающий)

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

До обязательного использования блока begin /rescue для ключевого слова 'retry' его можно было использовать таким способом, который он больше не может делать, повторяя вызов метода, несмотря на быть внутри этого метода .

Теперь он просто переходит к выражению 'begin'.

Но я не уверен в этом, и мне нужно подтверждение. И если да, есть ли какая-либо форма для восстановления такого рода использования?

Спасибо.

    
1
  1. "существует ли какая-либо форма для восстановления такого рода использования" Извините, неясно: чего вы хотели, чтобы retry было выполнено?
    2019-05-08 16: 30: 26Z
  2. Извините, мне просто интересно, можно ли его использовать для получения того же результата, что и в первом примере, перед тем как его заставят оказаться внутри "begin /rescue" блок. Кажется, для меня это была возможность вызвать метод с обновленным параметром.
    2019-05-08 16: 35: 10Z
  3. Первый пример не работает в Ruby 2.6. В строке 4 появляется сообщение об ошибке: недопустимая повторная попытка (SyntaxError)
    2019-05-08 16: 36: 11Z
  4. @ tadman Я знаю, я обнаружил, что он был вынужден находиться внутри спасательного блока в Ruby 2.3.1 (до этого он работал)
    2019-05-08 16: 42: 25Z
1 ответ                              1                         

Ваш WHILE не ведет себя как обычный while, поскольку в вашем случае i<3 оценивается во время вызова один раз . Оператор while оценивает его каждый раз.

Если вы хотите написать эквивалент while, важно, чтобы ваше условие было чем-то, что может быть оценено, а не тем, что уже оценено.

Это можно исправить, приняв Proc в качестве условия:

def so_long_as(cond)
  loop do
    return unless cond.call

    yield
  end
end

Тогда вы называете это так:

i = 0
so_long_as(-> { i < 3 }) do
  print i
  i += 1
end

Где это сейчас печатает 012 и правильно завершается.

Важно отметить, что retry работает только в контексте begin/end, а не в обычном методе, поэтому теперь вместо него нужно использовать redo:

i = 0
redone = false
so_long_as(-> { i < 3 }) do
  print i
  unless (redone)
    redone = true
    redo
  end
  i += 1
end

Где сейчас печатается 0012.

Произошли некоторые существенные изменения в работе redo и retry. о которых стоит почитать.

    
3
2019-05-08 16: 41: 15Z
  1. Спасибо! Это было действительно объяснительно. Чтобы я мог сделатьчто-то вроде этого: def WHILE(cond) begin return if not cond.call yield raise rescue retry end end i=0; WHILE(-> {i<3}) {print i; i+=1} Я знаю, что это довольно уродливо, и лучше использовать обычный цикл, но теперь я уверен, что мои мысли были для правильного пути.
    2019-05-10 13: 23: 41Z
  2. Таким образом, параметр метода просто необходимо было «обновить» (или переоценить) для его оценки в операторе return. И ключевое слово retry, казалось, делало это до 2.3.1.
    2019-05-10 13: 34: 51Z
  3. Вам нужно то, что в общих чертах называется "динамическим" значением, которое можно многократно оценивать для проверки на изменение условий. Лямбда (Proc) замыкание делает эту работу хорошо, отсюда первый аргумент. Они действительно сильно изменили способ работы retry в Ruby. Думаю, чтобы избежать двух разных и несколько противоречивых вещей в зависимости от контекста.
    2019-05-10 16: 34: 25Z
источник размещен Вот