Хотя блоки, Proc и lambda используются для схожих целей, между ними есть ключевые различия, которые важно понимать для профессиональной работы с Ruby.
{ }
или do...end
yield
в методахПример:
def call_block
yield if block_given?
end
call_block { puts "Это блок" }
Proc.new
или proc
Пример:
my_proc = Proc.new { |x| puts "Получено: #{x || 'нет значения'}" }
my_proc.call # Работает
my_proc.call(1, 2) # Тоже работает, берёт первый аргумент
lambda
или -> {}
(stabby lambda)Пример:
my_lambda = ->(x) { puts "Получено: #{x}" }
my_lambda.call(1) # Работает
# my_lambda.call # ArgumentError (не хватает аргументов)
Характеристика | Блок | Proc | Lambda |
---|---|---|---|
Объектность | Нет | Да | Да |
Проверка аргументов | - | Нет | Да |
return | Возврат из метода | Возврат из метода | Возврат из lambda |
Создание | Неявно в методах | Proc.new /proc | lambda /-> |
Вызов | yield | call /[] /() | call /[] /() |
p = Proc.new { |a, b| puts "#{a}, #{b}" }
l = ->(a, b) { puts "#{a}, #{b}" }
p.call(1) # Работает: "1, "
l.call(1) # ArgumentError
def proc_test
Proc.new { return "из Proc" }.call
"из метода"
end
def lambda_test
-> { return "из lambda" }.call
"из метода"
end
proc_test #=> "из Proc" (выход из метода)
lambda_test #=> "из метода" (возврат только из lambda)
Блок в Proc:
def block_to_proc(&block)
block
end
proc_obj = block_to_proc { |x| x * 2 }
proc_obj.call(3) #=> 6
Lambda в Proc:
lambda_obj = ->(x) { x * 2 }
Proc.new(&lambda_obj) # Конверсия возможна
Пример использования Proc для отложенного выполнения:
def create_callback(&block)
Proc.new do |data|
puts "Обрабатываю данные: #{data}"
block.call(data)
end
end
callback = create_callback { |d| puts "Результат: #{d * 2}" }
callback.call(5)
#=>
# Обрабатываю данные: 5
# Результат: 10
Резюмируем: хотя блоки, Proc и lambda выглядят похоже, они имеют важные семантические различия в поведении с аргументами, return и контексте выполнения. Блоки - это синтаксическая конструкция, Proc и lambda - объекты, при этом lambda ведёт себя больше как "настоящая" функция. Выбор между ними зависит от конкретных требований к поведению и необходимости работы с аргументами.
Для написания идиоматичного Ruby-кода важно понимать эти различия и использовать каждый инструмент в подходящих для него сценариях.