2010-08-24 14 views
5

मैंने रुबी सीखना शुरू कर दिया है, और मैंने कुछ ट्यूटोरियल पढ़े हैं और मैंने एक पुस्तक भी खरीदी है ("प्रोग्रामिंग रूबी 1.9 - द प्रोगैमैटिक प्रोग्रामर्स गाइड"), और मैं कुछ नया आया जो मैं मुझे पता है कि किसी भी अन्य भाषाओं में पहले नहीं देखा है (मैं एक PHP वेब डेवलपर के रूप में काम कर रहा हूँ)।रुबी में ब्लॉक और प्रो

ब्लॉक & प्रोसेस। मुझे लगता है कि मैं समझता हूं कि वे क्या हैं, लेकिन मुझे समझ में नहीं आता है कि वे इतने महान क्यों हैं, और कब और क्यों मुझे उनका उपयोग करना चाहिए। हर जगह मुझे लगता है कि वे कहते हैं कि रूबी में ब्लॉक और प्रोसेस एक महान विशेषता है, लेकिन मैं उन्हें समझ नहीं पा रहा हूं।

क्या कोई यहां मेरे जैसे कुछ रूबी-नौसिखियों को कुछ स्पष्टीकरण दे सकता है?

+0

क्लोजर पर अधिक जानकारी के लिए देखो, इससे यह बताने में मदद मिलेगी कि ब्लॉक और प्रोसेस कैसे काम करते हैं और वे किसके लिए उपयोगी हैं .. – Doon

उत्तर

13

ऐसी कई चीजें हैं जो ब्लॉक के बारे में अच्छी हैं। लिफ्ट पिच: ब्लॉक हमें क्रिया पास करते हैं, वैसे ही हम सामान्य रूप से लगभग डेटा पास करते हैं।

सबसे स्पष्ट स्तर यह है कि वे आपको अमूर्त चीजों को ऐसे कार्यों में छोड़ देते हैं जो अन्यथा संभव नहीं होंगे।उदाहरण के लिए, एक मामले ऐसे हैं जिनमें चीजों की एक सूची है को देखो और आप इसे फिल्टर करने के लिए केवल आइटम है कि कुछ कसौटी से मेल खाते हैं शामिल करना चाहते हैं:

int list[50] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50}; 
int evenNumbers[50] = {0}; 
int copyIndex = 0; 
for (int i = 0; i < 50; i++) { 
    if (list[i] % 2 == 0) { 
     evenNumbers[copyIndex++] = list[i]; 
    } 
} 

यहाँ आप कैसे लिखते हैं कि रूबी में:

list = 1..50 
listCopy = list.select {|n| n.even?} 

सभी सामान्य व्यस्त कार्य आपके कोड से और एक सार्थक नाम के साथ एक विधि में स्थानांतरित हो जाते हैं। हमें सरणी की प्रतिलिपि बनाने और इंडेक्स के माध्यम से जाने की परवाह नहीं है और यह सब - हम सिर्फ फ़िल्टर की गई सूची चाहते हैं। और यही select हमें देता है। ब्लॉक हमें इस मानक विधि में हमारे कस्टम तर्क को पारित करने की अनुमति देता है।

लेकिन इटरेटर एकमात्र ऐसा स्थान नहीं हैं जहां यह "hole in the middle pattern" उपयोगी है। उदाहरण के लिए, यदि आप File.open पर कोई ब्लॉक पास करते हैं, तो यह फ़ाइल खोल देगा, फ़ाइल के साथ ब्लॉक निष्पादित करेगा और फिर आपके लिए फ़ाइल बंद कर देगा।

ब्लॉक करने वाली एक और चीज हमें कॉलबैक का एक शक्तिशाली रूप है। उदाहरण के लिए, ब्लॉक के बिना, हम कुछ इस तरह (कैसे संवाद वास्तव में ऑब्जेक्टिव-सी कोको में काम के आधार पर) करने के लिए हो सकता है:

class Controller 
    def delete_button_clicked(item) 
    item.add_red_highlight 
    context = {:item => item} 
    dialog = Dialog.new("Are you sure you want to delete #{item}?") 
    dialog.ok_callback = :delete_OK 
    dialog.ok_receiver = self 
    dialog.cancel_callback = :cancel_delete 
    dialog.cancel_receiver = self 
    dialog.context = context 
    dialog.ask_for_confirmation 
    end 

    def delete_OK(sender) 
    delete(sender.context[:item]) 
    sender.dismiss 
    end 

    def cancel_delete(sender) 
    sender.context[:item].remove_red_highlight 
    sender.dismiss 
    end 
end 

Yowza। ब्लॉक के साथ, हम इस के बजाय कर सकता है (एक आम कई रूबी पुस्तकालयों में इस्तेमाल किया पद्धति के आधार पर):

class Controller 
    def delete_button_clicked(item) 
    item.add_red_highlight 
    Dialog.ask_for_confirmation("Are you sure you want to delete #{item}?") do |response| 
     response.ok { delete item } 
     response.cancel { item.remove_red_highlight } 
    end 
    end 
end 

वास्तव में ब्लॉक के दो स्तर है कि - do...end ब्लॉक और दो {} शैली ब्लॉक। लेकिन यह बहुत स्वाभाविक रूप से पढ़ता है, है ना? यह काम करता है क्योंकि एक ब्लॉक उस संदर्भ को कैप्चर करता है जो इसे बनाया गया है, इसलिए हमें self और item पास करने की आवश्यकता नहीं है।

प्रोसेस के लिए, वे केवल ब्लॉक के लिए एक ऑब्जेक्ट रैपर हैं। उनके लिए बहुत कुछ नहीं।

0

ये अवधारणाएं कार्यात्मक प्रोग्रामिंग से रूबी में अवधारणाओं से बंधी हुई हैं, इसलिए यह आपको उन भाषाओं और तकनीकों का उपयोग करने में सक्षम बनाती है जो आमतौर पर भाषाओं में पाए जाते हैं, जहां कार्य प्रथम श्रेणी के नागरिक होते हैं।

+0

वास्तव में, रूबी में ब्लॉक छोटे से नहीं आते हैं और दोनों भाषाओं में वे वस्तुएं काम नहीं करती हैं, हालांकि दोनों में, वे गुमनाम कार्यों की तरह दिखते हैं और कार्य करते हैं। जैसे। यहां तक ​​कि वाक्यविन्यास भी एक जैसे हैं। मिसाल में उदाहरण के लिए एक ब्लॉक 'ए: = [: x | x + 1] ' – OscarRyz

+0

@ ऑस्कररिज: मैं यहाँ नाइट चुनने की तरह हूं, लेकिन रूबी में ब्लॉक वास्तव में कार्य हैं और * ऑब्जेक्ट्स नहीं हैं। यही कारण है कि लोग कहते हैं कि वे बंद हैं - बंद एक प्रकार का कार्य है। उदाहरण के लिए, आप 'totally_an_object = {| n | लिख नहीं सकते हैं एन * 7} '- यह एक वाक्यविन्यास त्रुटि है। उस फ़ंक्शन का प्रतिनिधित्व करने वाली वास्तविक वस्तु प्राप्त करने के लिए आपको ब्लॉक के साथ 'proc' को कॉल करने की आवश्यकता है। ब्लॉक्स्स स्मॉलटाक में वास्तविक वस्तुएं थीं, लेकिन रुबी का संस्करण थोड़ा अलग है – Chuck

2

रूबी कक्षाओं में कई विधियों से ब्लॉक का उपयोग किया जाता है, और उनका उपयोग किया जाता है जहां PHP में आप कॉलबैक का उपयोग करेंगे।

[1,2,3,4,5].each {|i| print "#{i} "} 

[1,2,3,4,5].each do |i| 
    print "#{i} " 
end 

File.open('p014constructs.rb', 'r') do |f1| 
    while line = f1.gets 
    puts line 
    end 
end 

PHP5 ने अज्ञात कार्यों को प्रस्तुत किया; कॉलबैक का उपयोग करने के बजाय, आप एक अनाम फ़ंक्शन का उपयोग कर सकते हैं।

echo preg_replace_callback('~-([a-z])~', function ($match) { 
    return strtoupper($match[1]); 
}, 'hello-world'); 
+0

मैं इटरेटर का उपयोग करते समय ब्लॉक को समझता हूं और इसी तरह, यह अन्य सभी चीजें हैं जिन्हें मुझे नहीं मिलता है। (ज्यादातर procs, मुझे लगता है) – Nilks

+0

ब्लॉक बंद होने के बारे में हिस्सा में जोड़ें! (यानी आप ब्लॉक के दायरे के बाहर चर का उपयोग कर सकते हैं, जिसका अर्थ है कि आपको अस्थायी संरचनाओं का एक गुच्छा बनाना नहीं है, आदि) –

+0

रूबी 1.8 ब्लॉक "स्थानीय चर नहीं है" का अर्थ क्या है। मुझे लगता है कि आप पाएंगे कि आप सही नहीं हैं। – horseyguy

2

इसकी ब्लॉक तरीकों का उपयोग कर एक कोड ब्लॉक शुरू करने के लिए, आप वास्तव में ब्लॉक लेने और समारोह में एक पैरामीटर है जैसे कि यह प्रयोग कर रहे हैं के रूप में नहीं देखना महत्वपूर्ण है।

तो जब आप तो जैसे एक सरणी से अधिक पुनरावृति करने के लिए प्रत्येक विधि का उपयोग करें: | प्रवाह

superOverFlowArray.each { |flow| puts flow } 

आप ब्लॉक {भेज रहे हैं | प्रत्येक विधि में प्रवाह डालता है}। कोड इस ब्लॉक में सरणी के वर्तमान मूल्य को | प्रवाह | के स्थान पर भेजने के लिए रूबी को बता रहा है।

प्रक्रियाएं एक ब्लॉक लेती हैं और उन्हें एक चर में बनाती हैं। प्रक्रियाएं ऑब्जेक्ट उदाहरण हैं जो ब्लॉक धारण करती हैं। ब्लॉक को प्रोसेस के पैरामीटर के रूप में पास किया जाता है और जब आप उस प्रो इंस्टेंस पर 'कॉल' विधि को कॉल करते हैं तो निष्पादित किया जाता है।

तो यहाँ एक प्रोक उदाहरण है:

def category_and_title(category) 
    Proc.new { |title| "The title is: " + title + " in category: " + category } 
end 

myFirstTitle = category_and_title("Police Drama") 
mySecondTitle = category_and_title("Comedy") 

puts myFirstTitle.call("Law and Order") 
puts mySecondTitle.call("Seinfeld") 
puts myFirstTitle.call("CSI") 

प्रोक मूल श्रेणी में पारित किया गया था, प्रकार समूहीकरण के लिए एक सुविधाजनक तरीका की इजाजत दी याद रखेंगे।

0

ब्लॉक और प्रोसेस आपको पूर्ण ओवरहेड और विधियों की जटिलता के बिना कोड के छोटे बिट्स निकालने देते हैं।

भी map अपने आप में बहुत शक्तिशाली है, और jQuery इसी अवधारणा आसपास बनाया गया है:

['spite','rest','purpose'].map {|s| s << 'ful' } 

और आप यदि आवश्यक हो तो

['sprite','restful','luck'].map {|s| s << (s.end_with?('uck') ? 'i' : '') << 'ly' } 

एक चतुर ऑपरेटर '& नहीं है में तर्क फेंक कर सकते हैं 'इसका मतलब है "प्रतीक को एक प्रो में कनवर्ट करें और इसे कॉल करें", ताकि आप ऑब्जेक्ट स्ट्रिंग्स को कन्वर्ट कर सकें:

['spite',12,:purpose].map(&:to_s) 

और बंद करने और एक साधारण बंद करने के संयोजन को जोड़कर हम पाते हैं कि संख्याओं के आस-पास कहां दिखाई देते हैं। इस बल्कि अनाड़ी रूबी, लेकिन अधिकांश भाषाओं की तुलना में अधिक संक्षिप्त है:

last = -2 # this variable is accessed and changed within the closure 
    objs.sort.map do |o| 
    if (last + 1) != o 
     last = o 
     nil # not one more than previous so return nil 
    else 
     o 
    end 
    end.compact # compact removes nils 

जब आप किसी अन्य भाषा में यह फिर से लिखने शुरू आपको पता है कि यह कैसे सुविधाजनक है। यह आपको अपने कोड को छोटे परिचालनों में ढूढ़ने के लिए प्रोत्साहित करता है, इसलिए यह अधिक पुनः उपयोग करने योग्य और परीक्षण योग्य है।

1

प्रोसेस, जिन्हें क्लोजर या लैम्बडास भी कहा जाता है, रूबी में एक अवधारणा है जो विशेष रूप से एक नौसिखिया के लिए भ्रमित लगती है। संक्षेप में, procs आपको आसानी से कोड ब्लॉक पास करने की अनुमति देता है।एक उदाहरण, नीचे

hello = Proc.new do |x, y| 
     puts "i am a proc" 
     sum = x+y 
     puts "sum: #{sum}" 
    end 

अब कोड के इस ब्लॉक का उपयोग करने के लिए, बस हैलो पर विधि "कॉल" पर कॉल करें। ध्यान दें कि उपरोक्त उदाहरण तर्क x और y प्राप्त करता है जो कोड ब्लॉक उपयोग करता है। निम्न परिणाम उपज

hello.call(2, 3) 

:: इसलिए कि मैं नीचे किया है तर्क है जब आप प्रोक वस्तु बाहर फोन में पारित करने के लिए सुनिश्चित हो

i am a proc 
    sum: 5 

हुर्रे !! प्रो ऑब्जेक्ट बनाने का यह एक आसान तरीका था। यह कितना उपयोगी है? खैर, proc ऑब्जेक्ट्स आपको कोड के चारों ओर घूमने की अनुमति देता है। नीचे दिए गए उदाहरण में उपरोक्त उदाहरण में बनाई गई proc का उपयोग करके इसे बेहतर समझाया गया है। कि एम्परसेंड हस्ताक्षर "&" हैलो इससे पहले कि आप एक के रूप में एक proc वस्तु पारित करने के लिए अनुमति देता है अब चलो कुछ यादृच्छिक वर्ग बनाएँ,

class SomeClass 
     def initialize(&block) 
     @block = block 
     end 

     def output_value(x, y) 
     @block.call(x, y) 
     end 
    end 

, के SomeClass का एक उदाहरण बना सकते हैं,

some_class = SomeClass.new(&hello) 

नोट तर्क। इस प्रकार

some_class.output_value(1, 3) 

परिणाम आपको मिल है:

अंत में, उत्पादन एक मूल्य के जाने 2 तर्कों से गुजर रहा, नीचे की तरह से

i am a proc 
    sum: 4 

देखें !! यह इत्ना आसान है। आप कोड के एक हिस्से को पास करने में सक्षम हैं। प्रक्रिया इतनी उपयोगी है कि रूबी इसका उपयोग करता है। उम्मीद है कि यह बहुत उपयोगी था :)

संबंधित मुद्दे