2012-12-04 12 views
18

यदि मैं toSeq पर एक अपरिवर्तनीय Set संग्रह पर कॉल करता हूं तो मुझे ArrayBuffer मिलता है।स्कैला के ToSeq एक अपरिवर्तनीय सेट को एक परिवर्तनीय ArrayBuffer में क्यों परिवर्तित करता है?

scala> Set(1,2,3).toSeq // returns Seq[Int] = ArrayBuffer(1, 2, 3) 

यह मुझे आश्चर्यचकित करता है। अपरिवर्तनीय डेटा संरचनाओं का उपयोग करने पर स्कैला के जोर को देखते हुए, मैं एक म्यूटेबल ArrayBuffer के बजाय Vector या List जैसे अपरिवर्तनीय अनुक्रम को वापस पाने की अपेक्षा करता हूं। सेट तत्वों का लौटा आदेश निश्चित रूप से अनिर्धारित होना चाहिए, लेकिन ऐसा कोई अर्थपूर्ण कारण प्रतीत नहीं होता है कि यह आदेश भी उत्परिवर्तनीय होना चाहिए।

आम तौर पर, मैं अपेक्षा करता हूं कि स्कैला परिचालन हमेशा अपरिवर्तनीय नतीजों का उत्पादन न करें जब तक कि मैं स्पष्ट रूप से एक उत्परिवर्ती अनुरोध नहीं करता। यह सब मेरी धारणा है, लेकिन यह यहां एक गलत है, और मैंने वास्तव में एक समस्या को डीबग करने में एक घंटे बिताया जहां ArrayBuffer की अप्रत्याशित उपस्थिति ने match कथन में रनटाइम त्रुटि उत्पन्न की। मेरा फिक्स Set(...).toSeq को Set(...).toList में बदलना था, लेकिन यह एक हैक जैसा लगता है क्योंकि मेरे आवेदन के बारे में कुछ भी नहीं है जिसके लिए विशेष रूप से उस सूची की आवश्यकता होती है।

Set(...).toSeq एक उत्परिवर्तनीय वस्तु को स्कैला के कार्यान्वयन में एक दोष लौटाता है, या क्या कोई सिद्धांत है जो मैं यहां गलत समझ रहा हूं?

यह स्कैला 2.9.2 है।

+0

2,10-RC2 में फिक्स्ड: 'स्केला> Seq (1,2,3) .toSeq' ->' res0: Seq [इंट] = सूची (1, 2, 3) ' – senia

+0

@senia, क्या आपका मतलब' सेक (1,2,3) .toSq' के बजाय 'सेट (1,2,3) .toSeq' था? –

+1

कृपया परिवर्तन के लिए वोट दें: [एसआई -6570] (https://issues.scala-lang.org/browse/SI-6570) –

उत्तर

11

Here हाल ही में धागा है कि सेक का अपरिवर्तनीय होना चाहिए या नहीं।

रोलाण्ड कुहन:

collection.Seq नहीं होने mutators सब एक वैध रक्षा पर नहीं है!

म्यूटेबल varargs का उदाहरण बल्कि बदबूदार है।

हाल ही में,

scala> Set(1,2,3) 
res0: scala.collection.immutable.Set[Int] = Set(1, 2, 3) 

scala> res0.toSeq 
res1: Seq[Int] = ArrayBuffer(1, 2, 3) 

scala> res0.to[collection.immutable.Seq] 
res2: scala.collection.immutable.Seq[Int] = Vector(1, 2, 3) 
+0

ऐसा लगता है कि वर्तमान उत्तर "यह विवादास्पद है", और जुड़ा हुआ धागा अच्छा देता है चर्चा क्यों मूल प्रश्नों पर टिप्पणियों में भी लिंक देखें, क्योंकि उनमें से ऐसा लगता है कि विरोधी म्यूटबिलिस्ट अपना रास्ता प्राप्त कर रहे हैं। –

10

मैं मानता हूं कि यह थोड़ा अजीब है, लेकिन मुझे विश्वास नहीं है कि यह एक दोष है। सबसे पहले, इस पर विचार करें: Set.toSeq का संकलन समय प्रकार

() => Seq[Int] 

नहीं

() => ArrayBuffer[Int] 

ArrayBuffer सिर्फ लौटे वस्तु के रन-टाइम प्रकार होता है (शायद इसलिए कि Set.toSeq एक ArrayBuffer में जोड़ता है और फिर कनवर्ट किए बिना बस लौटाता है)।

तो, भले ही toSeq आप एक परिवर्तनशील वस्तु दे रहा है वापस, आप वास्तव में यह (कास्टिंग बिना उत्परिवर्तित नहीं कर सकते, या ArrayBuffer को मिलान पैटर्न - तो असली "अजीब" भाग स्काला आप पर पैटर्न मैच की सुविधा देता है मनमाने ढंग से कक्षाएं)। (आपको विश्वास करना है कि Set ऑब्जेक्ट पर नहीं है और इसे म्यूटेट नहीं करता है, लेकिन मुझे लगता है कि यह एक उचित धारणा है)।

इसे देखने का एक और तरीका यह है कि एक परिवर्तनीय प्रकार एक अपरिवर्तनीय प्रकार से सख्ती से अधिक विशिष्ट है। या, यह कहने का एक और तरीका यह है कि, प्रत्येक उत्परिवर्तनीय वस्तु को एक अपरिवर्तनीय वस्तु के रूप में भी माना जा सकता है: एक अपरिवर्तनीय वस्तु में गेटर होता है, और एक परिवर्तनीय वस्तु के पास एक गेटर और एक सेटटर होता है - लेकिन यह अभी भी एक गेटर है।

बेशक

, इस के साथ दुर्व्यवहार किया जा सकता है:

val x = new Seq[Int] { 
    var n: Int = 0 
    def apply(k: Int) = k 
    def iterator = { 
     n += 1 
     (0 to n).iterator 
    } 
    def length = n 
} 

x foreach println _ 
0 
1 

x foreach println _ 
0 
1 
2 

लेकिन, ठीक है, तो बहुत कुछ कर सकते हैं।

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

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