Значение по умолчанию для аргумента блока

#ruby

#рубиновый #ruby

Вопрос:

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

 def my_method(amp;print_if = Proc.new { true })
  internal_value = [1, 2, 3]
  puts "printing" if print_if.call(internal_value)
end

my_method { |array| array[1] == 2 }
 "printing"
 => nil
my_method { |array| array[1] == 3 }
 => nil
my_method
 "printing"
 => nil
  

Кажется, что мой лучший вариант — проверить наличие блока в методе. Это работает, это просто неуклюже

 def my_method(amp;print_if)
  internal_value = [1, 2, 3]
  puts "printing" if !block_given? || print_if.call(internal_value)
end

my_method { |array| array[1] == 2 }
 "printing"
 => nil
my_method { |array| array[1] == 3 }
 => nil
my_method
 "printing"
 => nil
  

Есть ли способ установить аргумент блока по умолчанию в Ruby? Пожалуйста, никаких ответов, которые полагаются на внешние библиотеки (даже Rails), просто пытаюсь выяснить, возможно ли это с помощью чистого Ruby.

Комментарии:

1. Вы также можете сделать (со своим вторым) примером print_if ||= -> { true }

2. Я только что заметил ваш второй блок кода после публикации моего ответа (с момента удаления), но в этом нет ничего плохого, поскольку код прекрасно описывает то, чего вы пытаетесь достичь. Я лично считаю print_if.nil? ? true : print_if.call(internal_value) , что читается лучше.

3. @Sergio, о чем ты говоришь?

4. Помните, что объявление блока в качестве аргумента влечет за собой довольно значительное снижение производительности, поскольку Ruby необходимо собирать много контекстной информации для блока, который может быть передан. По возможности используйте block_given? и yield в сочетании. Для легкого использования разница в основном академическая, но для кода, чувствительного к производительности, разница может быть существенной. Общее правило заключается в том, чтобы объявлять параметры блока только в том случае, если вам нужно переслать блок другому методу, и в этом случае вам все равно придется заплатить цену.

Ответ №1:

Вы можете использовать этот грязный хак:

 def my_method(print_if = -> (*args) { block_given? ? yield(*args) : true })
  internal_value = [1, 2, 3]
  puts "printing" if print_if.call(internal_value)
end
  

Но удобно ли это?

Комментарии:

1. Я думаю, что этот ответ довольно хорош в том смысле, что он доказывает, что в Ruby нет хорошего способа установки значений по умолчанию для аргументов, которые должны быть procs / lambdas / blocks . Я вообще не самый большой поклонник того, как Ruby позволяет передавать методы, но такова жизнь. Просто хотел посмотреть, есть ли ярлык, который я пропустил.