В Ruby существует несколько способов преобразования блоков кода в объекты Proc. Это полезно, когда нужно сохранить блок для последующего использования или передать его в несколько методов.
Самый распространённый способ - использовать амперсанд перед параметром метода:
def block_to_proc(&block)
block # Возвращаем преобразованный Proc
end
my_proc = block_to_proc { |x| x * 2 }
puts my_proc.call(3) # => 6
Особенности:
if block
Proc.new
без блока внутри метода захватывает переданный блок:
def make_proc
Proc.new # Преобразует неявный блок в Proc
end
pr = make_proc { "Hello" }
puts pr.call # => "Hello"
Важно: Если блок не передан, вызовет ArgumentError
Создаёт lambda (специальный тип Proc) из блока:
def make_lambda
lambda # Преобразует блок в lambda
end
l = make_lambda { |x, y| x + y }
puts l.call(2, 3) # => 5
Отличия lambda от обычного Proc:
return
работает как в методахВ Ruby 1.8 существовал метод proc
, который в новых версиях является синонимом Proc.new
:
p = proc { |x| x.upcase }
puts p.call("hello") # => "HELLO"
Способ | Тип создаваемого объекта | Проверяет аргументы | Поведение return |
---|---|---|---|
&block | Proc | Нет | Выход из метода |
Proc.new | Proc | Нет | Выход из метода |
lambda | Lambda | Да | Возврат из блока |
proc | Proc | Нет | Выход из метода |
class DeferredExecution
def initialize(&block)
@saved_proc = block
end
def execute(*args)
@saved_proc.call(*args)
end
end
deferred = DeferredExecution.new { |x| x * 3 }
puts deferred.execute(4) # => 12
def create_callbacks(default_proc, &custom_proc)
{
default: default_proc,
custom: custom_proc || Proc.new { |x| x }
}
end
callbacks = create_callbacks(Proc.new { |x| x * 2 }) { |x| x + 5 }
puts callbacks[:default].call(3) # => 6
puts callbacks[:custom].call(3) # => 8
&
для передачи в другие методыПример символизации:
def apply_operation(numbers, &operation)
numbers.map(&operation)
end
result = apply_operation([1, 2, 3]) { |x| x ** 2 }
# => [1, 4, 9]
Резюмируем: в Ruby есть несколько способов преобразовать блок в Proc - через явное указание параметра с &
, Proc.new
, lambda
или proc
. Выбор конкретного способа зависит от нужного поведения (обычный Proc vs lambda) и контекста использования. Преобразование блоков в Proc открывает возможности для создания гибких API и отложенного выполнения кода.