Block, Proc va Lambda — Ruby’ning eng o’ziga xos xususiyatlaridan biri: kodning o’zini qiymat sifatida metodga uzatish. Oldingi darslarda each do |x| ... end kabi yozuvlarni ko’p ishlatdik — ular aslida block edi. Endi bu mexanizmni chuqurroq tushunamiz.
Block / Proc / Lambda — uchalasi ham kod bo’lagini qiymat sifatida uzatish vositasi. Block — metodga bevosita biriktiriladigan, obyekt bo’lmagan kod bo’lagi. Proc va Lambda esa block’ning o’zgaruvchida saqlanadigan, mustaqil obyekt shakli (
Procklassi).
Block va yield
Har qanday metod yield kalit so’zi orqali o’ziga berilgan blokni ishga tushirishi mumkin:
def ikki_marta
yield
yield
end
ikki_marta { puts "Salom, UzbekDevs!" }
Salom, UzbekDevs!
Salom, UzbekDevs!
ikki_marta metodi o’zi hech qanday parametr olmaydi, lekin unga { ... } orqali berilgan blok yield chaqirilganda ishga tushadi — bunda ikki marta. Aynan shu mexanizm asosida each, map kabi barcha standart metodlar ishlaydi.
block_given? va blokka qiymat uzatish
Blok berilgan-berilmaganini oldindan tekshirish, va unga argument uzatish mumkin:
def sonni_qayta_ishla(son)
if block_given?
yield(son)
else
son
end
end
puts sonni_qayta_ishla(5) { |x| x * 10 }
puts sonni_qayta_ishla(5)
50
5
yield(son) — blokka son qiymatini argument sifatida uzatadi, blok ichida u x nomi bilan qabul qilinadi. block_given? blok berilmagan holatda metodning xatosiz ishlashini ta’minlaydi.
Proc — blokni obyekt sifatida saqlash
Blokni keyinroq ishlatish yoki boshqa metodga uzatish uchun Proc obyektiga aylantirish mumkin:
ikkilantir = Proc.new { |son| son * 2 }
puts ikkilantir.call(5)
puts ikkilantir.(10)
puts ikkilantir[15]
10
20
30
Proc.new blokni o’zgaruvchida saqlanadigan obyektga aylantiradi. Uni chaqirishning uch usuli bor: .call(5), .(10) yoki [15] — barchasi bir xil natija beradi, tanlov faqat uslub masalasi.
Lambda — qat’iyroq Proc
Lambda — Proc’ning maxsus turi, lekin ikki muhim jihatda farq qiladi: argumentlar sonini qat’iy tekshiradi va return boshqacha ishlaydi:
kvadrat = lambda { |son| son ** 2 }
kvadrat2 = ->(son) { son ** 2 }
puts kvadrat.call(4)
puts kvadrat2.call(5)
16
25
->(son) { ... } — lambda yaratishning qisqa (“stabby lambda”) shakli. Ikkalasi ham lambda { |son| ... } bilan bir xil natija beradi.
Proc va Lambda — muhim farq
Eng nozik, lekin muhim farq — return xatti-harakati va argument qat’iyligida:
def proc_sinov
ichki_proc = Proc.new { return 100 }
ichki_proc.call
puts "Bu qator bajarilmaydi"
end
def lambda_sinov
ichki_lambda = lambda { return 100 }
ichki_lambda.call
puts "Bu qator bajariladi"
end
puts proc_sinov
lambda_sinov
100
Bu qator bajariladi
Proc ichidagi return butun metoddan chiqib ketadi — shuning uchun proc_sinov da “Bu qator bajarilmaydi” hech qachon chop etilmaydi. Lambda ichidagi return esa faqat lambdaning o’zidan chiqadi, metod ijrosi davom etadi. Shu sababli amaliyotda alohida, mustaqil mantiq uchun ko’pincha lambda afzal ko’riladi.