_ (अंडरस्कोर) चर कहाँ और कैसे निर्दिष्ट किया जाता है?


81

अधिकांश _आईआरबी के अंतिम रिटर्न मूल्य के धारक के रूप में विशेष अर्थ से अवगत हैं , लेकिन ऐसा नहीं है जो मैं यहां पूछ रहा हूं।

इसके बजाय, मैं इसके बारे में पूछ रहा हूं _जब सादे-पुराने-रूबी-कोड में एक चर नाम के रूप में उपयोग किया जाता है। यहाँ यह विशेष व्यवहार करने के लिए प्रतीत होता है, "चर की परवाह नहीं" (एक ला प्रस्तावना ) के समान है। यहाँ कुछ उपयोगी उदाहरण हैं जो इसके अनूठे व्यवहार को दर्शाते हैं:

lambda { |x, x| 42 }            # SyntaxError: duplicated argument name
lambda { |_, _| 42 }.call(4, 2) # => 42
lambda { |_, _| 42 }.call(_, _) # NameError: undefined local variable or method `_'
lambda { |_| _ + 1 }.call(42)   # => 43
lambda { |_, _| _ }.call(4, 2)  # 1.8.7: => 2
                                # 1.9.3: => 4
_ = 42
_ * 100         # => 4200
_, _ = 4, 2; _  # => 2

ये सभी सीधे रूबी (साथ) में चलाए जा रहे थे puts एस में जोड़े गए) -नहीं IRB- अपनी अतिरिक्त कार्यक्षमता के साथ विवाद से बचने के लिए।

हालांकि यह मेरे अपने प्रयोग का एक परिणाम है, क्योंकि मुझे इस व्यवहार पर कहीं भी कोई प्रलेखन नहीं मिल रहा है (मूलतः यह खोज करने के लिए सबसे आसान बात नहीं है)। अंत में, मैं उत्सुक हूं कि यह सब आंतरिक रूप से कैसे काम करता है ताकि मैं ठीक से समझ सकूं कि इसमें क्या खास है _। इसलिए मैं प्रलेखन के संदर्भों के लिए पूछ रहा हूं, और, अधिमानतः, रूबी स्रोत कोड (और शायद रूबीस्पेक ) जो यह बताता है कि कैसे_ करता है कि रूबी व्यवहार करता है।

नोट: इस चर्चा के अधिकांश @ निक्लास बी के साथ सामने आए।

जवाबों:


54

"डुप्लिकेट तर्क नाम" त्रुटि को दबाने के लिए स्रोत में कुछ विशेष हैंडलिंग है। त्रुटि संदेश केवल shadowing_lvar_genअंदर दिखाई देता है parse.y, 1.9.3 संस्करण इस तरह दिखता है :

static ID
shadowing_lvar_gen(struct parser_params *parser, ID name)
{
    if (idUScore == name) return name;
    /* ... */

और इस तरह idUScoreसे परिभाषित किया गयाid.c है:

REGISTER_SYMID(idUScore, "_");

आपको इसी तरह की विशेष हैंडलिंग दिखाई देगी warn_unused_var:

static void
warn_unused_var(struct parser_params *parser, struct local_vars *local)
{
    /* ... */
    for (i = 0; i < cnt; ++i) {
        if (!v[i] || (u[i] & LVAR_USED)) continue;
        if (idUScore == v[i]) continue;
        rb_compile_warn(ruby_sourcefile, (int)u[i], "assigned but unused variable - %s", rb_id2name(v[i]));
    }
}

आप देखेंगे कि चेतावनी forलूप की दूसरी पंक्ति पर दबा दी गई है ।

_1.9.3 स्रोत में मुझे जो एकमात्र विशेष हैंडलिंग मिल सकती है वह ऊपर है: डुप्लिकेट नाम त्रुटि को दबा दिया गया है और अप्रयुक्त चर चेतावनी को दबा दिया गया है। उन दो चीजों के अलावा, _किसी भी अन्य की तरह एक सादे पुराने चर है। मैं (मामूली) विशिष्टता के बारे में कोई दस्तावेज नहीं जानता_

रूबी 2.0 में, idUScore == v[i]परीक्षण को warn_unused_varकॉल के साथ बदल दिया जाता है is_private_local_id:

if (is_private_local_id(v[i])) continue;
rb_warn4S(ruby_sourcefile, (int)u[i], "assigned but unused variable - %s", rb_id2name(v[i]));

और इसके is_private_local_idसाथ शुरू होने वाले चरों के लिए चेतावनी को दबा देता है _:

if (name == idUScore) return 1;
/* ... */
return RSTRING_PTR(s)[0] == '_';

बल्कि सिर्फ _खुद से। तो 2.0 loosens चीजों को थोड़ा बढ़ाते हैं।


1
मुझे आश्चर्य है कि अगर lambda { |_, _| _ }.call(4, 2)1.8 और 1.9 के बीच के व्यवहार में अंतर सिर्फ एक अनजाने में साइड-इफ़ेक्ट है? "सामान्य" परिस्थितियों में जहां चर नाम को उस क्रम में दोहराया नहीं जा सकता, जिसमें वे असाइन किए गए हैं, असंगत है।
एंड्रयू मार्शल

3
@AndrewMarshall: हां, मुझे लगता है कि "4 बनाम 2" मुद्दा सिर्फ 1.8 और 1.9 स्टैक को संभालने की कलाकारी है। केवल यह ध्यान देने योग्य होगा |_,_,...|क्योंकि डुप्लिकेट-त्रुटि को दबा दिया गया है।
म्यू बहुत छोटा है

2
@AndrewMarshall: मुझे आश्चर्य है कि अगर हर कोई हमारी पीठ के पीछे एक-दूसरे के चेंजलॉग्स को पढ़ रहा है।
mu

2
अच्छा लगा। मैंने मान लिया कि यह कुछ सरल होगा, बस दोहरे पैरामीटर नाम त्रुटि को दबा देना। रूबी वास्तव में एक बड़ी गड़बड़ है: डी
निकल्स बी

2
@ एमयू: बेशक, मुझे अभी तक एक व्याख्या की गई भाषा का वास्तव में साफ कार्यान्वयन देखना है (लुआ करीब आता है)।
निकल्स बी

24

_एक वैध पहचानकर्ता है। पहचानकर्ता केवल अंडरस्कोर नहीं कर सकते, वे अंडरस्कोर भी हो सकते हैं ।

_ = o = Object.new
_.object_id == o.object_id
# => true

आप इसे विधि नाम के रूप में भी उपयोग कर सकते हैं:

def o._; :_ end
o._
# => :_

बेशक, यह वास्तव में एक पठनीय नाम नहीं है, न ही यह पाठक को कोई जानकारी देता है कि चर क्या संदर्भित करता है या विधि क्या करती है।

IRB, विशेष रूप से, _अंतिम अभिव्यक्ति के मूल्य पर सेट होता है:

$ irb
> 'asd'
# => "asd"
> _
# => "asd"

जैसा कि यह स्रोत कोड में है , यह बस _अंतिम मान पर सेट होता है:

@workspace.evaluate self, "_ = IRB.CurrentContext.last_value"

कुछ रिपॉजिटरी की खोज की। यहाँ मैं क्या पाया:

फ़ाइल की अंतिम पंक्तियों पर id.c, कॉल है:

REGISTER_SYMID(idUScore, "_");

grepस्रोत के लिए idUScoreमुझे दो प्रासंगिक परिणाम दिए गए हैं:

shadowing_lvar_genऐसा तंत्र प्रतीत होता है जिसके माध्यम से एक ब्लॉक का औपचारिक पैरामीटर उसी नाम के एक चर की जगह लेता है जो दूसरे दायरे में मौजूद है। यह वह फ़ंक्शन है जो "डुप्लिकेट किए गए तर्क नाम" को बढ़ाता है।SyntaxError और "शेडिंग बाहरी स्थानीय चर" चेतावनी ।

के grepलिए स्रोत के बाद shadowing_lvar_gen, मैं रूबी 1.9.3 के लिए चैंज पर निम्नलिखित पाया :

Tue Dec 11 01:21:21 2007 युकीहिरो मात्सुमोतो

  • parse.y (shadowing_lvar_gen): "_" के लिए कोई डुप्लिकेट त्रुटि नहीं।

इस रेखा के मूल होने की संभावना है :

if (idUScore == name) return name;

इससे, मैं इस तरह की स्थिति में कटौती करता हूं, जैसे कि proc { |_, _| :x }.call :a, :bएक _चर दूसरे को छाया देता है।


यहाँ प्रश्न में है । इसने मूल रूप से इन दो पंक्तियों को पेश किया:

if (!uscore) uscore = rb_intern("_");
if (uscore == name) return;

एक समय से जब idUScoreअस्तित्व में भी नहीं था, जाहिरा तौर पर।


6
यह स्पष्ट नहीं होता सब पर क्यों lambda { |_, _| 42 }काम करता है, जबकि lambda { |x, x| 42 }ऐसा नहीं करता।
एंड्रयू मार्शल ने

@AndrewMarshall, ऐसा प्रतीत होता है कि आप सही हैं। |_, _|काम करता है, लेकिन |__, __|नहीं करता है। _कुछ विशेष अर्थ प्रतीत होते हैं, मैं देखूंगा कि क्या मैं रूबी स्रोत से किसी भी जानकारी को खोद सकता हूं।
मैथ्यूस मोरेरा

1
वैसे, आपका अपडेट, जबकि जानकारीपूर्ण, प्रासंगिक नहीं है क्योंकि यह केवल आईआरबी पर लागू होता है, जिसे मैंने विशेष रूप से अपने प्रश्न में कहा था जिसके बारे में मैं नहीं पूछ रहा था।
एंड्रयू मार्शल

1
चेंजलॉग प्रविष्टि को खोदने के लिए +1। सभी को C हैकर होना चाहिए :)
mu बहुत छोटा है

1
IRB स्रोत कोड के लिए +1। IRB.CurrentContext.last_value के बारे में जानना बहुत दिलचस्प है, भले ही यह प्रश्न के रूप में प्रासंगिक न हो। आईआरबी अंडरस्कोर के बारे में एक Google खोज से मैं यहां समाप्त हुआ।
जोश
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.