लट बनाम ब्रेस का उपयोग करना {}


112

माणिक के लिए नया, अपने नौसिखिया दस्ताने पर डाल दिया।

निम्नलिखित दो स्निपेट के बीच कोई अंतर (अस्पष्ट या व्यावहारिक) है?

my_array = [:uno, :dos, :tres]
my_array.each { |item| 
    puts item
}

my_array = [:uno, :dos, :tres]
my_array.each do |item| 
    puts item
end

मुझे लगता है कि ब्रेस सिंटैक्स आपको ब्लॉक को एक पंक्ति में रखने की अनुमति देगा

my_array.each { |item| puts item }

लेकिन उस के बाहर वहाँ एक दूसरे पर एक वाक्यविन्यास का उपयोग करने के लिए कोई सम्मोहक कारण हैं?


5
बड़ा सवाल है। मुझे भी दिलचस्पी है कि अनुभवी रूबिस्ट क्या पसंद करते हैं।
जोनाथन स्टर्लिंग


2
के संभावित डुप्लिकेट stackoverflow.com/questions/533008/...
जॉन Topley


1
आप do block का एक लाइनर भी लिख सकते हैं, हालाँकि यह वास्तव में केवल तभी उपयोगी है जब कुछ करना पसंद है ("my_arar.each do। Item; put item; end")), लेकिन यह iral या pry में बिना eval और उद्धरण के काम करता है। ऐसी स्थिति में आ सकता है जब उसे प्राथमिकता दी जाए। हालांकि मुझसे मत पूछो। यह एक और विषय है जिसकी जांच की जानी है।
डगलस जी। एलन

जवाबों:


101

रूबी रसोई की किताब का कहना है कि ब्रैकेट सिंटैक्स की तुलना में उच्च पूर्वता क्रम हैdo..end

ध्यान रखें कि ब्रैकेट सिंटैक्स में do..end सिंटैक्स की तुलना में अधिक पूर्वता होती है। निम्नलिखित दो स्निपेट कोड पर विचार करें:

1.upto 3 do |x|
  puts x
end

1.upto 3 { |x| puts x }
# SyntaxError: compile error

दूसरा उदाहरण केवल तब काम करता है जब कोष्ठक का उपयोग किया जाता है, 1.upto(3) { |x| puts x }


8
आह, समझ गया। इसलिए पूर्वता क्रम के कारण, जब आप उपयोग करते हैं, तो आप ब्लॉक को एक अतिरिक्त पैरामीटर के रूप में पास कर रहे हैं, लेकिन जब आप कोष्ठक का उपयोग करते हैं तो आप ब्लॉक को पास कर रहे हैं विधि विधि के परिणामों के पहले पैरामीटर के रूप में (एस) छोडा।
एलन स्टॉर्म

2
मैं अक्सर छोटे उत्तरों को प्राथमिकता देता हूं लेकिन bkdir का उत्तर बहुत अधिक स्पष्ट है।
याकूत

71

इसमें कुछ समय पुराने सवाल है, लेकिन मैं के बारे में में और व्याख्या करने की कोशिश करना चाहते हैं {}औरdo .. end

जैसा पहले कहा जाता है

ब्रैकेट सिंटैक्स में do..end की तुलना में अधिक पूर्वता क्रम होता है

लेकिन यह कैसे फर्क करता है:

method1 method2 do
  puts "hi"
end

इस स्थिति में, do..endमेथ 1 को ब्लॉक के साथ बुलाया जाएगा और मेथड 1 को तर्क 1 के रूप में पास किया जाएगा! जो के बराबर हैmethod1(method2){ puts "hi" }

लेकिन अगर तुम कहो

method1 method2{
  puts "hi"
}

फिर मेथड 2 को ब्लॉक के साथ बुलाया जाएगा फिर लौटे मान को मेथड 1 में तर्क के रूप में पास किया जाएगा। के बराबर हैmethod1(method2 do puts "hi" end)

def method1(var)
    puts "inside method1"
    puts "method1 arg = #{var}"
    if block_given?
        puts "Block passed to method1"
        yield "method1 block is running"
    else
        puts "No block passed to method1"
    end
end

def method2
    puts"inside method2"
    if block_given?
        puts "Block passed to method2"
        return yield("method2 block is running")
    else
        puts "no block passed to method2"
        return "method2 returned without block"
    end
end

#### test ####

method1 method2 do 
    |x| puts x
end

method1 method2{ 
    |x| puts x
}

#### आउटपुट ####

#inside method2
#no block passed to method2
#inside method1
#method1 arg = method2 returned without block
#Block passed to method1
#method1 block is running

#inside method2
#Block passed to method2
#method2 block is running
#inside method1
#method1 arg = 
#No block passed to method1

39

आम तौर पर, सम्मेलन का उपयोग {}तब करना होता है जब आप एक छोटा ऑपरेशन कर रहे होते हैं, उदाहरण के लिए, एक विधि कॉल या तुलना इत्यादि, ताकि यह सही साबित हो सके:

some_collection.each { |element| puts element }

लेकिन अगर आपके पास थोड़ा जटिल तर्क है जो कई लाइनों में जाता है तो उपयोग करें do .. end:

1.upto(10) do |x|
  add_some_num = x + rand(10)
  puts '*' * add_some_num
end

मूल रूप से, यह नीचे आता है, यदि आपका ब्लॉक लॉजिक कई लाइनों में जाता है और उसी लाइन पर फिट नहीं किया जा सकता है तो उपयोग करें do .. endऔर यदि आपका ब्लॉक लॉजिक सरल है और बस एक सरल / एकल लाइन कोड है तो उपयोग करें {}


6
मैं मल्टी-लाइन ब्लॉक के लिए do / end का उपयोग करने से सहमत हूं, लेकिन मैं ब्रेसिज़ के साथ जाऊंगा यदि मैं ब्लॉक के अंत तक अतिरिक्त तरीकों का पीछा कर रहा हूं। Stylistically मुझे पसंद है {...}। Method () (मेथड) (ओवर) do ... end.method ()। मेथड, लेकिन वह सिर्फ मुझे हो सकता है।
टिन मैन

1
सहमत, हालांकि मैं एक सार्थक चर के लिए ब्लॉक के साथ एक विधि का परिणाम असाइन करना पसंद करता हूं और फिर उस पर एक और विधि को इस तरह से कॉल करता हूं result_with_some_condition = method{|c| c.do_something || whateever}; result_with_some_condition.another_methodकि बस इसे थोड़ा और आसानी से समझ में आता है। लेकिन आम तौर पर मैं एक ट्रेन के मलबे से बचता था।
nas

मुझे आश्चर्य है, यह शैली इतनी लोकप्रिय क्यों है। क्या "हम हमेशा इसे इस तरह से करते हैं" के अलावा इसका कोई कारण है?
आईजीईएल

9

चुनने के लिए दो आम शैलियों रहे हैं do endबनाम { }रूबी में ब्लॉक के लिए:

रूबी द्वारा पटरियों पर पहली और बहुत ही सामान्य शैली को लोकप्रिय बनाया गया था, और यह एकल बनाम बहु-पंक्ति के एक सरल नियम पर आधारित है:

  • { }सिंगल-लाइन ब्लॉकों के लिए ब्रेसिज़ का उपयोग करें
  • do endमल्टी-लाइन ब्लॉकों के लिए उपयोग करें

यह समझ में आता है क्योंकि do-end एक-लाइनर में बुरी तरह से पढ़ता है, लेकिन मल्टी-लाइन ब्लॉक के लिए, }अपनी ही लाइन पर क्लोजिंग हैंग करना छोड़ना endमाणिक में उपयोग होने वाली हर चीज के साथ असंगत है , जैसे मॉड्यूल, क्लास और मेथड परिभाषाएं ( defआदि) ।) और नियंत्रण ढांचे ( if, while, case, आदि)

दूसरा, कम अक्सर देखा शैली अर्थ, या "के रूप में जाना जाता है Weirich ब्रेसिज़ ", देर से, महान rubyist जिम वेइरिच द्वारा प्रस्तावित:

  • do endप्रक्रियात्मक ब्लॉकों के लिए उपयोग करें
  • { }कार्यात्मक ब्लॉकों के लिए ब्रेसिज़ का उपयोग करें

इसका मतलब यह है कि जब ब्लॉक को उसके वापसी मूल्य के लिए मूल्यांकन किया जाता है , तो इसे चेनेबल होना चाहिए, और {}ब्रेसिज़ विधि के लिए अधिक समझ में आता है।

दूसरी ओर, जब ब्लॉक का उसके दुष्प्रभावों के लिए मूल्यांकन किया जाता है , तो रिटर्न वैल्यू का कोई परिणाम नहीं होता है, और ब्लॉक सिर्फ कुछ "कर" रहा है, इसलिए यह जंजीर होने का कोई मतलब नहीं है।

सिंटैक्स में यह अंतर ब्लॉक के मूल्यांकन के बारे में दृश्य अर्थ बताता है, और आपको इसके वापसी मूल्य की परवाह करनी चाहिए या नहीं।

उदाहरण के लिए, यहां ब्लॉक का रिटर्न वैल्यू हर आइटम पर लागू होता है:

items.map { |i| i.upcase }

हालाँकि, यहाँ यह ब्लॉक के रिटर्न मान का उपयोग नहीं कर रहा है। यह प्रक्रियात्मक रूप से काम कर रहा है , और इसके साथ एक साइड-इफ़ेक्ट कर रहा है:

items.each do |item|
  puts item
end

सिमेंटिक शैली का एक और लाभ यह है कि आपको ब्रेस को बदलने की ज़रूरत नहीं है, केवल अंत में ब्लॉक करने के लिए एक पंक्ति जोड़ी गई है।

अवलोकन के रूप में, संयोग से कार्यात्मक ब्लॉक अक्सर एक-लाइनर होते हैं, और प्रक्रियात्मक ब्लॉक (जैसे कॉन्फ़िगरेशन) बहु-पंक्ति होते हैं। इसलिए, वेइरिच शैली का अनुसरण रेल की शैली के समान ही दिखता है।


1

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

date = Timecop.freeze(1.year.ago) { format_date(Time.now) }
customer = Timecop.freeze(1.year.ago) { create(:customer) }

क्या ये उपचारात्मक या कार्यात्मक हैं?

और मेरे हिसाब से लाइन काउंट की बात बेकार है। मुझे पता है, चाहे 1 या अधिक लाइनें हों, और मुझे वास्तव में शैली को सिर्फ इसलिए बदलना चाहिए क्योंकि मैंने लाइनें जोड़ी या हटा दी हैं?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.