Как вы используете блоки Ruby для условного выполнения чего-либо? - PullRequest
4 голосов
/ 02 мая 2011

Я недавно приобрел книгу Семь языков за семь недель и перечитывал главу о Ruby. В разделе, который вводит блоки (стр. 40), приведен пример кода, который иллюстрирует использование блоков с целью условного выполнения чего-либо:

in_case_of_emergency do
  use_credit_card
  panic
end

def in_case_of_emergency
  yield if emergency?
end

Этот код не имеет большого смысла для меня, и книга не дает большого объяснения. Мне было интересно, если бы один из вас, Руби-гуру, возражал бы помочь мне разобраться с этим.

Как вы можете иметь блок и функцию с одинаковым именем? Как бы вы определили «чрезвычайную ситуацию»? Я даже не могу создать блок в IRB, не жалуясь:

NoMethodError: undefined method `in_case_of_emergency' for main:Object
    from (irb):1
    from :0

А как бы вы вызвали этот код, чтобы продемонстрировать, как он работает? Спасибо!

Ответы [ 3 ]

10 голосов
/ 02 мая 2011

Во-первых: оба находятся в неправильном порядке.Вам нужно определить in_case_of_emergency first.

Second: Вы не называете блоки;следовательно, неверно, что есть две вещи с именем in_case_of_emergency.Один - это определение функции, а второй - функция , вызывающая той же функции.

Итак, пошагово:

def emergency?
  return rand(2) == 0
end

Допустим, выиметь эту функцию, которая возвращает true половину времени и false половину времени, случайно.(Мальчик, это много чрезвычайных ситуаций!) Тогда:

def in_case_of_emergency
  yield if emergency?
end

Это определяет функцию с именем in_case_of_emergency.При вызове он выполняет yield if emergency?, который является оператором yield, измененным условным условием if.Это синтаксический сахар для

if emergency?()
  yield
end

Обратите внимание, что Ruby не требует скобок для вызова функций, поэтому мы можем отбросить их;и если внутри if есть только один оператор, вы можете написать его в той же строке, что и выше (устраняя необходимость в end).

Далее у нас есть вызов функции:

in_case_of_emergency do
  use_credit_card
  panic
end

Вызывает функцию, которую мы только что определили, in_case_of_emergency, передавая ей блок для выполнения.Это два оператора (use_credit_card, panic), которые будут выполняться yield - но только если emergency? оценивается как true.

Имеет ли это сейчас смысл?

2 голосов
/ 02 мая 2011

это просто, вот метод:

def in_case_of_emergency 
  yield if emergency?
end

и это вызов вашего метода:

in_case_of_emergency do
   use_credit_card
   panic
end 

где

do
   use_credit_card
   panic
end 

это аргумент. Методы Ruby могут неявно принимать блоки в качестве аргументов. Что происходит то yield выполнит указанный вами блок. В вашем случае yield if emergency? означает «выполнить предоставленный блок, если выполнены условия».

0 голосов
/ 02 мая 2011

Добавляя к другим ответам, может быть легче понять блоки, если вы отбросите ключевое слово yield и обработаете блоки такими методами, как Procs, которым они на самом деле являются.

# for testing purposes, let's always have `emergency?` return `true`
def emergency?
  true
end  

def in_case_of_emergency(&block)
  block.call if emergency?
end

in_case_of_emergency do
  puts "AHH! Emergency! Help!", "Seriously, I'm freaking out!"
end

Посмотрите, насколько легче понять, что блок на самом деле является аргументом?

...