2011-09-08 14 views
9

तो, "प्रभावशाली के लिए स्कैला" के माध्यम से अपना रास्ता काम करते समय मैंने खुद को आश्चर्यचकित कर दिया: क्या आप अनुक्रम के बिना लूप के लिए स्कैला का उपयोग कर सकते हैं?अनुक्रम के बिना स्कैला में लूप के लिए?

उदाहरण के लिए, पुस्तक में एक अभ्यास है जो आपको काउंटर ऑब्जेक्ट बनाने के लिए कहता है जिसे Integer.MAX_VALUE से पहले नहीं बढ़ाया जा सकता है।

var c = new Counter 
for(i <- 0 to Integer.MAX_VALUE) c.increment() 

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

मुझे लगता है मैं इस के बजाय कर सकता है कि:

var c = new Counter 
while(c.value < Integer.MAX_VALUE) c.increment() 

लेकिन वहाँ बयान के लिए के साथ पाश के लिए एक पारंपरिक सी शैली करने के लिए कोई तरीका है?

उत्तर

17

वास्तव में, 0 to N वास्तव में 0 से N को पूर्णांकों के साथ कुछ भी पॉप्युलेट नहीं है। इसके बजाय यह scala.collection.immutable.Range का एक उदाहरण बनाता है, जो फ्लाई पर उत्पन्न सभी पूर्णांकों के लिए अपनी विधियों को लागू करता है।

आपके द्वारा चलाए गए त्रुटि केवल इसलिए है क्योंकि length विधि के अनुबंध को बनाए रखने के लिए आपको Int के सकारात्मक भाग में तत्वों की संख्या (चाहे वे वास्तव में मौजूद हैं या नहीं) फिट करने में सक्षम होना चाहिए। 1 to Int.MaxValue ठीक काम करता है, जैसा कि 0 until Int.MaxValue करता है। और उत्तरार्द्ध वह है जो आपका लूप वैसे भी कर रहा है (to में सही एंडपॉइंट शामिल है, until इसे छोड़ देता है)।

वैसे भी, क्योंकि स्कैला for सी for की तुलना में एक बहुत अलग (अधिक सामान्य) प्राणी है, संक्षिप्त उत्तर नहीं है, आप बिल्कुल वही काम नहीं कर सकते हैं। लेकिन संभवतः आप for (जो शायद आप जितनी जल्दी चाहें उतनी जल्दी नहीं कर सकते हैं, क्योंकि कुछ प्रदर्शन जुर्माना है)।

4

हां और नहीं, यह निर्भर करता है कि आप क्या पूछ रहे हैं।

def fromTo(from : Int, to : Int) : Stream[Int] = 
    if(from > to) { 
    Stream.empty 
    } else { 
    // println("one more.") // uncomment to see when it is called 
    Stream.cons(from, fromTo(from + 1, to)) 
    } 

तो: आप पहली बार है कि अनुक्रम का निर्माण करने के बिना पूछ रहे हैं, तो आप पूर्णांकों का एक दृश्य से अधिक पुनरावृति कर सकते हैं, तो आप, उदाहरण के लिए धाराओं का इस्तेमाल करके कर सकते हैं हाँ

for(i <- fromTo(0, 5)) println(i) 

लेखन अपने हैनेक्स्ट को परिभाषित करके अपना इटरेटर और अगला दूसरा विकल्प है।

यदि आप पूछ रहे हैं कि आप "मूल" लूप लिखने के लिए 'फॉर' सिंटैक्स का उपयोग कर सकते हैं, यानी एक लूप जो किसी ऑब्जेक्ट के उदाहरण द्वारा उत्पादित मानों को पुन: सक्रिय करने के बजाय कुछ मूल पूर्णांक को बढ़ाकर काम करता है, तो जवाब है, जहां तक ​​मुझे पता है, नहीं। जैसा कि आप जानते हैं, 'के लिए' जनरेटर और उनके प्रकार के घोंसले के आधार पर, फ्लैटमैप, फ़िल्टर, मानचित्र और/या foreach (FilterMonadic विशेषता में परिभाषित सभी) के संयोजन के लिए 'सिंथैक्टिक चीनी' समझें। आप कुछ पाश संकलन और देखने के लिए कि वे किस तरह का विस्तार कर रहे हैं

scalac -Xprint:refchecks 

के साथ अपने संकलक मध्यवर्ती प्रतिनिधित्व मुद्रित करने के लिए कोशिश कर सकते हैं।

+0

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

+0

'से'' की परिभाषा को 'स्ट्रीम' (या' इटरेटर') साथी ऑब्जेक्ट पर 'iterate' विधि का उपयोग करके और सरल बनाया जा सकता है। कुछ के साथ कुछ: 'def से करने के लिए (से: Int, to: Int) = Stream.iterate (से, से - से) (_ + 1) '। लेकिन 'से लेकर तक' का उपयोग करना अधिक मूर्खतापूर्ण है और एक ही चीज़ प्राप्त करता है। –

2

वहां इनमें से एक समूह है, लेकिन मुझे इस समय उन्हें गुगल करने पर परेशान नहीं किया जा सकता है। निम्नलिखित सुंदर विहित है:

@scala.annotation.tailrec 
def loop(from: Int, until: Int)(f: Int => Unit): Unit = { 
    if (from < until) { 
    f(from) 
    loop(from + 1, until)(f) 
    } 
} 

loop(0, 10) { i => 
    println("Hi " + i) 
} 
5

वाह, एक सरल प्रश्न के लिए कुछ अच्छा तकनीकी जवाब (जो अच्छा है!) लेकिन मामले में किसी को भी सिर्फ एक सरल जवाब की तलाश में है:

//start from 0, stop at 9 inclusive 
for (i <- 0 until 10){ 
    println("Hi " + i) 
} 

//or start from 0, stop at 9 inclusive 
for (i <- 0 to 9){ 
    println("Hi " + i) 
} 

रेक्स के रूप में बताया, "को" अधिकार भी शामिल है एंडपॉइंट, "जब तक" इसे छोड़ देता है।