Блоки в Ruby — это одна из самых мощных и характерных особенностей языка, позволяющая инкапсулировать куски кода и передавать их методам.
Блок — это анонимная функция, которая:
[1, 2, 3].each { |x| puts x * 2 }
[1, 2, 3].each do |x|
square = x * x
puts "Квадрат #{x} равен #{square}"
end
Сами по себе блоки не являются объектами, но могут быть преобразованы в Proc-объекты:
block = proc { |x| x * 2 }
puts block.call(3) #=> 6
Блоки сохраняют контекст, в котором были определены:
def multiplier(factor)
proc { |n| n * factor }
end
double = multiplier(2)
puts double.call(5) #=> 10
Методы могут принимать блоки неявно или явно:
def greet
yield if block_given?
end
greet { puts "Привет!" }
def process(&block)
block.call
end
process { puts "Выполняю блок" }
Характеристика | Блок | Proc | Lambda |
---|---|---|---|
Объектность | Нет | Да | Да |
Проверка аргументов | - | Нет | Да |
return | Возврат из метода | Возврат из Proc | Возврат из lambda |
Синтаксис | {}/do-end | Proc.new/proc | lambda/stabby (->) |
[1, 2, 3].map { |x| x * x } #=> [1, 4, 9]
File.open("file.txt") do |file|
puts file.read
end # Файл автоматически закрывается
RSpec.describe "MyClass" do
it "should do something" do
# тест
end
end
def benchmark
start = Time.now
yield
Time.now - start
end
time = benchmark { heavy_computation }
def with_logging
puts "Начало выполнения"
result = yield
puts "Завершение выполнения. Результат: #{result}"
result
end
with_logging { 2 + 2 }
#=>
# Начало выполнения
# Завершение выполнения. Результат: 4
Блоки "запоминают" контекст, в котором были созданы:
def counter
count = 0
-> { count += 1 }
end
c = counter
puts c.call #=> 1
puts c.call #=> 2
Резюмируем: блоки в Ruby — это мощный инструмент для создания гибкого и выразительного кода. Они позволяют инкапсулировать поведение, реализовывать шаблон обратного вызова (callback), создавать DSL и многое другое. Понимание блоков — ключ к профессиональному владению Ruby, так как они лежат в основе многих идиом языка.
Для эффективной работы с Ruby важно не только уметь использовать блоки, но и понимать разницу между блоками, Proc и lambda, а также знать, когда каждый из этих инструментов наиболее уместен.