रूबी ब्लॉक्स, प्रॉक्स और लैम्ब्डा।
वे क्या हैं?
वे कैसे काम करते हैं?
वे एक दूसरे से कैसे भिन्न हैं?
आप इस पोस्ट को पढ़कर वह और बहुत कुछ सीखेंगे!
विषयसूची
- 1 रूबी ब्लॉक्स को समझना
- 2 रूबी यील्ड कीवर्ड
- 3 इम्प्लिसिट बनाम एक्सप्लिसिट ब्लॉक्स
- 4 कैसे जांचें कि कोई ब्लॉक दिया गया था या नहीं
- 5 लैम्ब्डा क्या है?
- 6 लैम्ब्डा बनाम प्रॉक्स
- 7 क्लोजर्स
- 8 बाइंडिंग क्लास
- 9 वीडियो ट्यूटोरियल
- 10 समापन
- 10.1 संबंधित
रूबी ब्लॉक्स को समझना
रूबी ब्लॉक्स छोटे अनाम फंक्शन्स हैं जिन्हें मेथड्स में पास किया जा सकता है।
ब्लॉक्स do / end स्टेटमेंट में संलग्न होते हैं या ब्रैकेट्स {} के बीच, और उनके कई तर्क हो सकते हैं।
तर्क नाम दो पाइप | वर्णों के बीच परिभाषित होते हैं।
यदि आपने पहले each का उपयोग किया है, तो आपने ब्लॉक्स का उपयोग किया है!
यहां एक उदाहरण है:
# फॉर्म 1: सिंगल-लाइन ब्लॉक्स के लिए अनुशंसित
[1, 2, 3].each { |num| puts num }
^^^^^ ^^^^^^^^ ब्लॉक ब्लॉक आर्गुमेंट्स बॉडी
# फॉर्म 2: मल्टी-लाइन ब्लॉक्स के लिए अनुशंसित [1, 2, 3].each do |num| puts num end
एक रूबी ब्लॉक उपयोगी है क्योंकि यह आपको थोड़ा सा लॉजिक (कोड) सहेजने और बाद में इसका उपयोग करने की अनुमति देता है।
यह कुछ ऐसा हो सकता है जैसे डेटा को फ़ाइल में लिखना, तुलना करना कि क्या एक एलिमेंट दूसरे के बराबर है, या यहां तक कि एक त्रुटि संदेश प्रिंट करना।
रूबी यील्ड कीवर्ड
रूबी में yield का क्या अर्थ है?
Yield एक रूबी कीवर्ड है जो ब्लॉक को कॉल करता है जब आप इसका उपयोग करते हैं।
यह है कि मेथड्स ब्लॉक्स का उपयोग कैसे करते हैं!
जब आप yield कीवर्ड का उपयोग करते हैं, तो ब्लॉक के अंदर का कोड चलेगा और अपना काम करेगा।
ठीक वैसे ही जैसे जब आप एक नियमित रूबी मेथड को कॉल करते हैं।
यहां एक उदाहरण है:
def print_once
yield
end
print_once { puts "Block is being run" }
यह print_once को पास किए गए किसी भी ब्लॉक को चलाता है, परिणामस्वरूप, "Block is being run" स्क्रीन पर प्रिंट होगा।
क्या आप जानते थे…
कि yield का उपयोग कई बार किया जा सकता है?
हर बार जब आप yield कॉल करते हैं, तो ब्लॉक चलेगा, इसलिए यह उसी मेथड को फिर से कॉल करने जैसा है।
उदाहरण:
def print_twice
yield
yield
end
print_twice { puts "Hello" }
# "Hello"
# "Hello"
और मेथड्स की तरह ही…
आप yield को कितने भी तर्क पास कर सकते हैं।
उदाहरण:
def one_two_three
yield 1
yield 2
yield 3
end
one_two_three { |number| puts number * 10 }
# 10, 20, 30
ये तर्क तब ब्लॉक के तर्क बन जाते हैं।
इस उदाहरण में number।
इम्प्लिसिट बनाम एक्सप्लिसिट ब्लॉक्स
ब्लॉक्स "एक्सप्लिसिट" या "इम्प्लिसिट" हो सकते हैं।
एक्सप्लिसिट का अर्थ है कि आप इसे अपने पैरामीटर सूची में एक नाम देते हैं।
आप एक एक्सप्लिसिट ब्लॉक को दूसरे मेथड में पास कर सकते हैं या बाद में उपयोग के लिए इसे वेरिएबल में सहेज सकते हैं।
यहां एक उदाहरण है:
def explicit_block(&block)
block.call # yield के समान
end
explicit_block { puts "Explicit block called" }
&block पैरामीटर पर ध्यान दें…
यही वह तरीका है जिससे आप ब्लॉक का नाम परिभाषित करते हैं!
कैसे जांचें कि कोई ब्लॉक दिया गया था या नहीं
यदि आप ब्लॉक के बिना yield करने की कोशिश करते हैं तो आपको no block given (yield) त्रुटि मिलेगी।
आप block_given? मेथड से जांच सकते हैं कि कोई ब्लॉक पास किया गया है या नहीं।
उदाहरण:
def do_something_with_block return "No block given" unless block_given? yield end
यह त्रुटि को रोकता है यदि कोई आपके मेथड को ब्लॉक के बिना कॉल करता है।
लैम्ब्डा क्या है?
एक लैम्ब्डा एक ब्लॉक और उसके पैरामीटर्स को कुछ विशेष सिंटैक्स के साथ परिभाषित करने का एक तरीका है।
आप इस लैम्ब्डा को बाद में उपयोग के लिए वेरिएबल में सहेज सकते हैं।
रूबी लैम्ब्डा को परिभाषित करने का सिंटैक्स ऐसा दिखता है:
say_something = -> { puts "This is a lambda" }
आप वैकल्पिक सिंटैक्स का भी उपयोग कर सकते हैं:
->के बजायlambda।
लैम्ब्डा को परिभाषित करने से उसके अंदर का कोड नहीं चलेगा, ठीक वैसे ही जैसे मेथड को परिभाषित करने से मेथड नहीं चलता, आपको इसके लिए call मेथड का उपयोग करना होगा।
उदाहरण:
say_something = -> { puts "This is a lambda" }
say_something.call # "This is a lambda"
lambda को call करने के अन्य तरीके भी हैं, यह जानना अच्छा है कि वे मौजूद हैं, हालांकि, मैं स्पष्टता के लिए call के साथ बने रहने की सलाह देता हूं।
यहां सूची है:
my_lambda = -> { puts "Lambda called" }
my_lambda.call
my_lambda.()
my_lambda[]
my_lambda.===
लैम्ब्डा तर्क भी ले सकते हैं, यहां एक उदाहरण है:
times_two = ->(x) { x * 2 }
times_two.call(10) # 20
यदि आप गलत संख्या में तर्क पास करते हैं तो lambda एक अपवाद उठाएगा, ठीक एक नियमित मेथड की तरह।
लैम्ब्डा बनाम प्रॉक्स
प्रॉक्स एक बहुत समान अवधारणा हैं…
अंतरों में से एक है उन्हें कैसे बनाया जाता है।
उदाहरण:
my_proc = Proc.new { |x| puts x }
कोई समर्पित Lambda क्लास नहीं है। एक lambda सिर्फ एक विशेष Proc ऑब्जेक्ट है। यदि आप Proc से इंस्टेंस मेथड्स को देखते हैं, तो आप देखेंगे कि वहां एक lambda? मेथड है।
अब:
एक प्रॉक्स लैम्ब्डा से अलग व्यवहार करता है, विशेष रूप से जब तर्कों की बात आती है:
t = Proc.new { |x,y| puts "I don't care about arguments!" }
t.call # "I don't care about arguments!"
procs और lambdas के बीच एक और अंतर है कि वे return स्टेटमेंट पर कैसे प्रतिक्रिया करते हैं।
एक lambda सामान्य रूप से return करेगा, जैसे एक नियमित मेथड।
लेकिन एक proc वर्तमान संदर्भ से return करने का प्रयास करेगा।
मेरा मतलब यहां है:
यदि आप निम्नलिखित कोड चलाते हैं, तो आप देखेंगे कि कैसे proc एक LocalJumpError अपवाद उठाता है।
कारण यह है कि आप टॉप-लेवल संदर्भ से return नहीं कर सकते।
इसे आज़माएं:
# काम करना चाहिए
my_lambda = -> { return 1 }
puts "Lambda result: #{my_lambda.call}"
# अपवाद उठाना चाहिए
my_proc = Proc.new { return 1 }
puts "Proc result: #{my_proc.call}"
यदि proc एक मेथड के अंदर था, तो return कॉल करना उस मेथड से वापस आने के बराबर होगा।
यह निम्नलिखित उदाहरण में प्रदर्शित किया गया है।
def call_proc
puts "Before proc"
my_proc = Proc.new { return 2 }
my_proc.call
puts "After proc"
end
p call_proc # "Before proc" प्रिंट करता है लेकिन "After proc" नहीं
यहां एक सारांश है कि procs और lambdas कैसे भिन्न हैं:
- लैम्ब्डा
-> {}से परिभाषित होते हैं और प्रॉक्सProc.new {}से। - प्रॉक्स वर्तमान मेथड से रिटर्न करते हैं, जबकि लैम्ब्डा लैम्ब्डा से ही रिटर्न करते हैं।
- प्रॉक्स सही संख्या में तर्कों की परवाह नहीं करते, जबकि लैम्ब्डा अपवाद उठाएंगे।
इस सूची को देखते हुए, हम देख सकते हैं कि lambdas नियमित मेथड की तुलना में procs की तुलना में बहुत अधिक करीब हैं।
क्लोजर्स
रूबी प्रॉक्स और लैम्ब्डा का एक और विशेष गुण भी है। जब आप एक रूबी प्रॉक्स बनाते हैं, तो यह वर्तमान निष्पादन स्कोप को अपने साथ कैप्चर कर लेता है।
इस अवधारणा को, जिसे कभी-कभी क्लोजर कहा जाता है, का अर्थ है कि एक proc स्थानीय वेरिएबल्स और मेथड्स जैसे मानों को उस संदर्भ से ले जाएगा जहां इसे परिभाषित किया गया था।
वे वास्तविक मान नहीं ले जाते, बल्कि उनके लिए एक संदर्भ ले जाते हैं, इसलिए यदि प्रॉक्स बनने के बाद वेरिएबल्स बदलते हैं, तो प्रॉक्स के पास हमेशा नवीनतम संस्करण होगा।
एक उदाहरण देखते हैं:
def call_proc(my_proc)
count = 500
my_proc.call
end
count = 1
my_proc = Proc.new { puts count }
p call_proc(my_proc) # यह क्या प्रिंट करता है?
इस उदाहरण में हमारे पास एक स्थानीय count वेरिएबल है, जो 1 पर सेट है।
हमारे पास my_proc नामक एक प्रॉक्स भी है, और एक call_proc मेथड जो किसी भी प्रॉक्स या लैम्ब्डा को चलाता है ( call मेथड के माध्यम से) जिसे तर्क के रूप में पास किया जाता है।
आपको क्या लगता है यह प्रोग्राम क्या प्रिंट करेगा?
ऐसा लगेगा कि 500 सबसे तार्किक निष्कर्ष है, लेकिन 'क्लोजर' प्रभाव के कारण यह 1 प्रिंट करेगा।
ऐसा इसलिए होता है क्योंकि प्रॉक्स count के मान का उपयोग उस स्थान से कर रहा है जहां प्रॉक्स परिभाषित किया गया था, और वह मेथड परिभाषा के बाहर है।
बाइंडिंग क्लास
रूबी प्रॉक्स और लैम्ब्डा इस स्कोप जानकारी को कहां संग्रहीत करते हैं?
आइए आपको Binding क्लास के बारे में बताते हैं…
जब आप binding मेथड के माध्यम से एक Binding ऑब्जेक्ट बनाते हैं, तो आप कोड में इस बिंदु पर एक 'एंकर' बना रहे होते हैं।
इस बिंदु पर परिभाषित हर वेरिएबल, मेथड और क्लास बाद में इस ऑब्जेक्ट के माध्यम से उपलब्ध होगा, भले ही आप पूरी तरह से अलग स्कोप में हों।
उदाहरण:
def return_binding
foo = 100
binding
end
# बाइंडिंग के लिए धन्यवाद foo उपलब्ध है,
# भले ही हम उस मेथड के बाहर हों
# जहां यह परिभाषित किया गया था।
puts return_binding.class
puts return_binding.eval('foo')
# यदि आप सीधे foo प्रिंट करने की कोशिश करते हैं तो आपको त्रुटि मिलेगी।
# कारण यह है कि foo को मेथड के बाहर कभी परिभाषित नहीं किया गया था।
puts foo
दूसरे शब्दों में, binding ऑब्जेक्ट के संदर्भ में कुछ निष्पादित करना वैसा ही है जैसे वह कोड उसी स्थान पर था जहां वह binding परिभाषित किया गया था ('एंकर' रूपक याद रखें)।
आपको सीधे binding ऑब्जेक्ट्स का उपयोग करने की आवश्यकता नहीं है, लेकिन यह जानना अभी भी अच्छा है कि यह एक चीज है 🙂
वीडियो ट्यूटोरियल
समापन
इस पोस्ट में आपने सीखा कि ब्लॉक्स कैसे काम करते हैं, रूबी प्रॉक्स और लैम्ब्डा के बीच अंतर और आपने उस "क्लोजर" प्रभाव के बारे में भी सीखा जो जब भी आप एक ब्लॉक बनाते हैं तो होता है।
एक चीज जो मैंने कवर नहीं की वह है करी मेथड।
यह मेथड आपको आवश्यक कुछ या सभी तर्कों को पास करने की अनुमति देता है।
यदि आप केवल आंशिक संख्या में तर्क पास करते हैं तो आपको इन तर्कों के साथ एक नया प्रॉक्स मिलेगा जो पहले से 'प्री-लोडेड' हैं, जब सभी तर्क प्रदान किए जाते हैं तो प्रॉक्स निष्पादित होगा।
मुझे आशा है कि आपको यह पोस्ट पसंद आई!
नीचे दिए गए फॉर्म में सदस्यता लेना और इसे अपने दोस्तों के साथ शेयर करना न भूलें 🙂