रूबी में स्ट्रिंग बनाते समय फावड़ा ऑपरेटर (<<) को प्लस-बराबरी (+ =) पर क्यों पसंद किया जाता है?


156

मैं रूबी कोन्स के माध्यम से काम कर रहा हूं।

test_the_shovel_operator_modifies_the_original_stringमें कोआन about_strings.rb निम्नलिखित टिप्पणी में शामिल हैं:

रूबी प्रोग्रामर स्ट्रॉन्ग ऑपरेटर (<<) से अधिक स्ट्रॉन्ग बिल्डिंग बनाते समय प्लस ऑपरेटर (+ =) के बराबर होते हैं। क्यों?

मेरा अनुमान है कि इसमें गति शामिल है, लेकिन मुझे हुड के तहत कार्रवाई समझ में नहीं आती है जिसके कारण फावड़ा ऑपरेटर तेज हो जाएगा।

क्या कोई कृपया इस वरीयता के पीछे के विवरण को समझाने में सक्षम होगा?


4
फावड़ा ऑपरेटर एक नई स्ट्रिंग ऑब्जेक्ट (स्मृति की लागत) बनाने के बजाय स्ट्रिंग ऑब्जेक्ट को संशोधित करता है। वाक्यविन्यास सुंदर नहीं है? सीएफ Java और .NET में StringBuilder कक्षाएं हैं
कर्नल पैनिक

जवाबों:


257

सबूत:

a = 'foo'
a.object_id #=> 2154889340
a << 'bar'
a.object_id #=> 2154889340
a += 'quux'
a.object_id #=> 2154742560

इसलिए <<नया बनाने के बजाय मूल स्ट्रिंग को बदल देता है। इसका कारण यह है कि रूबी के a += bलिए सिंटैक्टिक शॉर्टहैंड है a = a + b(वही अन्य <op>=ऑपरेटरों के लिए जाता है ) जो एक असाइनमेंट है। दूसरी ओर <<एक अन्य नाम है, concat()जो रिसीवर को जगह में बदल देता है।


3
धन्यवाद, नूडल! तो, संक्षेप में, << तेज है क्योंकि यह नई वस्तुओं का निर्माण नहीं करता है?
एरिनब्रोवन 19

1
यह बेंचमार्क कहता है कि Array#joinइस्तेमाल करने से धीमा है <<
एंड्रयू ग्रिम

5
एजकेस के लोगों में से एक ने प्रदर्शन संख्याओं के साथ एक स्पष्टीकरण पोस्ट किया है: स्ट्रिंग्स के बारे में थोड़ा अधिक
सिनसिनाटी जो

8
ऊपर @CincinnatiJoe लिंक टूटा हुआ प्रतीत होता है, यहाँ एक नया है: स्ट्रिंग्स के बारे में एक छोटी सी बात
jasoares

जावा के लोगों के लिए: रूबी में '+' ऑपरेटर स्ट्रिंगबुलस्ट ऑब्जेक्ट के
माध्यम से संलग्न

79

प्रदर्शन प्रमाण:

#!/usr/bin/env ruby

require 'benchmark'

Benchmark.bmbm do |x|
  x.report('+= :') do
    s = ""
    10000.times { s += "something " }
  end
  x.report('<< :') do
    s = ""
    10000.times { s << "something " }
  end
end

# Rehearsal ----------------------------------------
# += :   0.450000   0.010000   0.460000 (  0.465936)
# << :   0.010000   0.000000   0.010000 (  0.009451)
# ------------------------------- total: 0.470000sec
# 
#            user     system      total        real
# += :   0.270000   0.010000   0.280000 (  0.277945)
# << :   0.000000   0.000000   0.000000 (  0.003043)

70

एक दोस्त जो रूबी को अपनी पहली प्रोग्रामिंग भाषा के रूप में सीख रहा है, उसने रूबी कॉन्स श्रृंखला पर रूबी में स्ट्रिंग्स से गुजरते हुए मुझसे यही सवाल पूछा। मैंने इसे निम्नलिखित सादृश्य का उपयोग करके समझाया;

आपके पास एक गिलास पानी है जो आधा भरा हुआ है और आपको अपने गिलास को फिर से भरना है।

पहला तरीका आप इसे एक नया गिलास लेकर, एक नल से पानी के साथ आधा भरकर और फिर अपने पीने के गिलास को फिर से भरने के लिए इस दूसरे आधे-भरे गिलास का उपयोग करें। आप ऐसा हर बार करते हैं जब आपको अपने गिलास को फिर से भरना पड़ता है।

दूसरा तरीका यह है कि आप अपना आधा पूरा ग्लास लें और नल से सीधे पानी के साथ रिफिल करें।

दिन के अंत में, आपके पास अपने गिलास को फिर से भरने के लिए आवश्यक हर बार एक नया गिलास चुनने के लिए चुनने के लिए आपके पास अधिक ग्लास होंगे।

वही फावड़ा ऑपरेटर और प्लस बराबर ऑपरेटर पर लागू होता है। साथ ही बराबर ऑपरेटर हर बार एक नया 'ग्लास' चुनता है, जबकि उसे अपने गिलास को फिर से भरना पड़ता है जबकि फावड़ा ऑपरेटर सिर्फ उसी गिलास को लेता है और उसे रिफिल करता है। दिन के अंत में प्लस बराबर ऑपरेटर के लिए अधिक 'ग्लास' संग्रह।


2
महान सादृश्य, यह प्यार करता था।
GMA

5
महान सादृश्य लेकिन भयानक निष्कर्ष। आपको यह जोड़ना होगा कि चश्मा किसी और द्वारा साफ किया जाता है ताकि आपको उनकी परवाह न करनी पड़े।
फ़िलिप बार्टूज़ी

1
महान सादृश्य, मुझे लगता है कि यह एक अच्छा निष्कर्ष है। मुझे लगता है कि इस बारे में कम है कि किसको कांच साफ करना है और कितने चश्मे का इस्तेमाल करना है। आप सोच सकते हैं कि कुछ एप्लिकेशन अपनी मशीनों पर मेमोरी की सीमा को आगे बढ़ा रहे हैं और यह कि मशीन एक बार में कुछ निश्चित चश्मे को ही साफ कर सकती हैं।
चार्ली एल

11

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

@ नूडल से स्वीकृत उत्तर से पता चलता है कि << मौजूदा ऑब्जेक्ट को जगह में संशोधित करता है, जबकि + = एक नई वस्तु बनाता है। इसलिए आपको यह विचार करने की आवश्यकता है कि क्या आप नए मूल्य को प्रतिबिंबित करने के लिए स्ट्रिंग के सभी संदर्भ चाहते हैं, या क्या आप मौजूदा संदर्भों को अकेला छोड़ना चाहते हैं और स्थानीय रूप से उपयोग करने के लिए एक नया स्ट्रिंग मूल्य बनाना चाहते हैं। यदि आपको अपडेट किए गए मान को प्रतिबिंबित करने के लिए सभी संदर्भों की आवश्यकता है, तो आपको << का उपयोग करने की आवश्यकता है। यदि आप अन्य संदर्भों को अकेले छोड़ना चाहते हैं, तो आपको + = का उपयोग करने की आवश्यकता है।

एक बहुत ही सामान्य मामला यह है कि स्ट्रिंग के लिए केवल एक संदर्भ है। इस मामले में, शब्दार्थ अंतर कोई फर्क नहीं पड़ता है और अपनी गति के कारण << पसंद करना स्वाभाविक है।


10

क्योंकि यह तेज़ है / स्ट्रिंग की प्रतिलिपि नहीं बनाता है <-> कचरा कलेक्टर को चलाने की आवश्यकता नहीं है।


जबकि उपरोक्त उत्तर अधिक विस्तार देते हैं, यह एकमात्र ऐसा है जो उन्हें पूर्ण उत्तर के लिए एक साथ रखता है। यहाँ कुंजी को "आपके ऊपर के निर्माण" शब्द के अर्थ में लगता है कि इसका मतलब है कि आपको मूल तार की आवश्यकता नहीं है या इसकी आवश्यकता नहीं है।
ड्रू वर्ली

यह उत्तर एक झूठे आधार पर आधारित है: अल्पकालिक वस्तुओं को आवंटित करना और मुक्त करना दोनों किसी भी आधे सभ्य सभ्य जीसी में अनिवार्य रूप से स्वतंत्र हैं। यह सी में स्टैक आवंटन के रूप में कम से कम और malloc/ की तुलना में काफी तेज है free। इसके अलावा, कुछ और आधुनिक रूबी कार्यान्वयन संभवतः ऑब्जेक्ट आवंटन और स्ट्रिंग संघनन को पूरी तरह से अनुकूलित करेंगे। OTOH, म्यूटिंग ऑब्जेक्ट GC प्रदर्शन के लिए भयानक है।
जॉर्ग डब्ल्यू मित्तग

4

जबकि अधिकांश उत्तर कवर +=धीमा है, क्योंकि यह एक नई प्रतिलिपि बनाता है, यह ध्यान रखना आवश्यक है कि +=और विनिमेय << नहीं हैं ! आप अलग-अलग मामलों में प्रत्येक का उपयोग करना चाहते हैं।

उपयोग <<करने से इंगित किए गए किसी भी चर को बदल दिया जाएगा baजब हम नहीं चाहते हैं तो हम यहां उत्परिवर्तन करते हैं।

2.3.1 :001 > a = "hello"
 => "hello"
2.3.1 :002 > b = a
 => "hello"
2.3.1 :003 > b << " world"
 => "hello world"
2.3.1 :004 > a
 => "hello world"

क्योंकि +=एक नई प्रतिलिपि बनाता है, यह किसी भी चर को छोड़ देता है जो इसे अपरिवर्तित होने की ओर इशारा करता है।

2.3.1 :001 > a = "hello"
 => "hello"
2.3.1 :002 > b = a
 => "hello"
2.3.1 :003 > b += " world"
 => "hello world"
2.3.1 :004 > a
 => "hello"

जब आप छोरों के साथ काम कर रहे हैं तो इस अंतर को समझना आपको बहुत सारे सिरदर्द से बचा सकता है!


2

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


टिप के लिए धन्यवाद, माइकल! मैंने रूबी में अभी तक ऐसा नहीं किया है, लेकिन यह निश्चित रूप से भविष्य में काम आएगा।
एरिनबोर्न
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.