7

मैं अज्ञात फ़ंक्शन बनाने के लिए प्लेसहोल्डर के रूप में _ का उपयोग कर रहा हूं, और समस्या यह है कि मैं भविष्यवाणी नहीं कर सकता कि स्कैला मेरे कोड को कैसे परिवर्तित करने जा रहा है। अधिक सटीक रूप से, यह गलती से निर्धारित करता है कि अज्ञात फ़ंक्शन मैं "बड़ा" कैसे चाहता हूं।अज्ञात फ़ंक्शन को परिभाषित करने के लिए अंडरस्कोर को नियंत्रित करने के नियम क्या हैं?

List(1,2,3) foreach println(_:Int) //error ! 
List(1,2,3) foreach (println(_:Int)) //work 
List(1,2,3) foreach(println(_:Int)) //work 

-Xprint:typer का उपयोग करना मैं देख सकता हूँ स्काला "एक बड़ा गुमनाम समारोह" में पहले एक बदल देती है:

x$1 => List(1,2,3) foreach(println(x$1:Int)) 

काम किया 2th 3th जो मैं चाहता में सही परिवर्तन कर रहे हैं।

... foreach (x$1 => println(x$1:Int)) 

यह क्यों? नियम क्या है?

उत्तर

8

सरल नियम अंडरस्कोर का दायरा निर्धारित करने:

  1. अंडरस्कोर एक पद्धति के लिए एक तर्क है, तो दायरे से बाहर कि विधि, अन्यथा संबंधित नीचे दिए गए नियमों हो जाएगा;
  2. यदि अंडरस्कोर() या {} द्वारा सीमित अभिव्यक्ति के अंदर है, तो अंडरस्कोर वाले सबसे कम ऐसे डिलीमीटर का उपयोग किया जाएगा;
  3. अन्य सभी चीजें बराबर होती हैं, संभवतः सबसे बड़ी अभिव्यक्ति का उपयोग किया जाएगा।

तो, द्वारा # 1 नियम, println((x: Int) => x) के बजाय, दायरे से बाहर (सहित) println रखा जाएगा।

नियम # 2 के अनुसार, बाद के दो उदाहरणों में ब्रांड्स द्वारा सीमित फ़ंक्शन होगा, इसलिए (x => println(x: Int))

नियम # 3 के द्वारा, पहला उदाहरण संपूर्ण अभिव्यक्ति होगी, क्योंकि कोई सीमित संश्लेषण नहीं है।

4

मेरा मानना ​​है कि श्री सोब्राल का जवाब गलत है। वास्तविक नियम Scala Language Reference, खंड 6.23, उपशीर्षक "बेनामी कार्यों के लिए प्लेसहोल्डर सिंटेक्स" में पाया जा सकता है।

एकमात्र नियम यह है कि innermost अभिव्यक्ति जो सही ढंग से अंडरस्कोर अज्ञात फ़ंक्शन के दायरे को परिभाषित करती है। इसका मतलब है कि श्री सोब्राल के पहले दो नियम सही हैं, क्योंकि एक विधि कॉल अभिव्यक्ति है और अभिव्यक्ति को संश्लेषित करना इसका अर्थ नहीं बदलता है। लेकिन तीसरा नियम सत्य के विपरीत है: अन्य सभी चीजें समान हैं, सबसे छोटी अभिव्यक्ति जो समझ में आती है।

दुर्भाग्य से, व्यवहार के लिए मेरी व्याख्या श्री लस्कोवस्की ने अपने पहले उदाहरण के लिए मनाया थोड़ा सा शामिल और सट्टा है। जब

List(1,2,3) foreach println(_:Int) 

स्कैला रीड-इवल-प्रिंट लूप पर टाइप किया गया है।त्रुटि संदेश है:

error: type mismatch; 
found : Unit 
required: Int => ? 
       List(1,2,3) foreach println(_:Int) 
             ^

आप उदाहरण एक छोटा सा भिन्न हो तो:

List(1,2,3).foreach println(_:Int) 

त्रुटि संदेश को समझने में आसान है -

error: missing arguments for method foreach in class List; 
follow this method with `_' if you want to treat it as a partially applied function 
      List(1,2,3).foreach println(_:Int) 
        ^

चीजें एक को समझने के लिए थोड़ा बेहतर, scala पर कॉल करें: scala -Xprint:parser, जो कि प्रत्येक अभिव्यक्ति को उपयोगकर्ता द्वारा टाइप किया गया है, अभिव्यक्ति का कारण पार्सर द्वारा मुद्रित किया जाता है। Laskowski का पहला उदाहरण के लिए (कचरा का एक बहुत है, जो मैं छोड़ दूँगा। साथ ही), अभिव्यक्ति पार्सर द्वारा समझा

((x$1: Int) => List(1, 2, 3).foreach(println((x$1: Int)))) 

दूसरा उदाहरण के लिए है, पार्सर के संस्करण

((x$1: Int) => List(1, 2, 3).foreach.println((x$1: Int))) 

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

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

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