2011-06-13 21 views
9

में exhaustiveness चेकों संरक्षण एक्सट्रैक्टर्स के साथ मामला वर्ग विरासत की जगह मैं एक साधारण वर्ग पदानुक्रम उस के साथ vertexes के कई अलग-अलग प्रकार के मामले वर्गों का उपयोग करना कार्यान्वित एक ग्राफ की तरह संरचना का प्रतिनिधित्व करता है:स्काला

sealed trait Node 

sealed abstract case class Vertex extends Node 
case class Arc extends Node 

case class VertexType1 (val a:Int) extends Vertex 
case class VertexType2 (val b:Int) extends Vertex 

यह मैं लिखने की अनुमति देता इस तरह मैच ब्लॉक:

def test (x: Node) = x match { 
    case _ : Arc => "got arc" 
    case _ : Vertex => "got vertex" 
} 

या इस तरह:

def test (x: Node) = x match { 
    case _ : Arc => "got arc" 
    case c : Vertex => c match { 
    case _ : VertexType1(a) => "got type 1 vertex " + a 
    case _ : VertexType2(a) => "got type 2 vertex " + a 
    } 
} 

ध्यान दें कि इस कार्यान्वयन में निम्न गुण हैं:

1) यह मिलान ब्लॉक को लिखने की अनुमति देता है जो आर्क और लंबवत के बीच अंतर करता है, लेकिन विशिष्ट वर्टेक्स प्रकारों के बीच नहीं, बल्कि ब्लैक मिलान प्रकारों के बीच भिन्नता से मेल खाता है।

2) दोनों चरम-प्रकार-विशिष्ट और गैर-वर्टेक्स-प्रकार-विशिष्ट मिलान ब्लॉक में पैटर्न मिलान की थकावट की जांच की जाती है।

हालांकि, केस कक्षाओं से विरासत को बहिष्कृत किया गया है, और संकलक गैर-पत्ती नोड्स (यानी, ऊपर दिए गए उदाहरण में, आर्क और शिखर के बीच अंतर करने के लिए, लेकिन वर्टेक्स प्रकारों के बीच अंतर करने के लिए) के बजाय निकालने वाले का उपयोग करने का सुझाव देता है। ।

प्रश्न: क्या केस क्लास विरासत का उपयोग किए बिना एक समान श्रेणी पदानुक्रम को कार्यान्वित करना संभव है, लेकिन अभी भी ऊपर दिखाए गए दोनों उपयोग मामलों में कंपाइलर द्वारा किए गए पैटर्न थकाऊपन जांच हैं?

EDIT: मैंने VertexType कक्षाओं में एक कन्स्ट्रक्टर पैरामीटर जोड़ा है ताकि मैच केवल प्रकारों पर नहीं किया जा सके।

sealed trait Node 

sealed abstract class Vertex extends Node 
class Arc extends Node 

class VertexType1 (val a:Int) extends Vertex 
class VertexType2 (val b:Int) extends Vertex 

object VertexType1 { 
    def unapply (x : VertexType1) : Some[Int] = Some(x.a) 
} 

object VertexType2 { 
    def unapply (x : VertexType2) : Some[Int] = Some(x.b) 
} 

और परीक्षण कोड:

मामले वर्गों के बिना मेरे वर्तमान कार्यान्वयन इस प्रकार है

def test (x: Node) = x match { 
    case _ : Arc => "got arc" 
    case v : Vertex => v match { 
    case VertexType1(a) => "got vertex type 1 " + a 
    } 
} 

मैं दूसरे खंड में गैर संपूर्ण मैच बारे में एक चेतावनी की उम्मीद (VertexType2 है कभी मेल नहीं खाता), लेकिन कोई नहीं है।

दरअसल, 2.9.0-आरसी 3 से पहले स्कैला कंपाइलर्स एक चेतावनी उत्पन्न करते हैं जो मुझे देखने की उम्मीद है, लेकिन आरसी 3 (2.9.0 और 2.9.0-1 समेत) से शुरू होने वाले संस्करण, जो भ्रमित नहीं हैं।

+1

बस पूर्णता के लिए: यह स्कैला 2.10 में तय किया गया है। (स्कैला 2.9.एक्स में एक रिग्रेशन था) – gourlaysama

उत्तर

0

scala-lang.org से प्रशस्ति पत्र:

एक पैटर्न मैच के चयनकर्ता एक सील बंद वर्ग का एक उदाहरण है, तो पैटर्न मिलान के संकलन चेतावनी जो इस बात का एक सेट का निदान फेंकना कर सकते हैं पैटर्न पूर्ण नहीं हैं, यानी कि रन-टाइम पर एक मैच एररबीइंग की संभावना है।

2

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

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

आपने अपने उदाहरण में जो किया है उसे पैटर्न पर मिलान-मिलान कहा जाता है। यदि आप केवल यह करना चाहते हैं, तो आपको केस कक्षाओं और न ही निकालने वालों की आवश्यकता नहीं है। आप इसे हर वर्ग के साथ कर सकते हैं। तो आप बस मामला संशोधक को हटा सकते हैं।

तो निष्कर्ष निकालने के लिए: पैटर्न की थकावट सीलबंद वर्ग हिराची द्वारा हासिल की जाती है। पैटर्न मिलान एक्स्ट्रेक्टर्स और केस क्लास द्वारा हासिल किया जाता है जो उत्तरार्द्ध अक्सर उपयोग किए जाने वाले कार्यों के आकर्षक मानक कार्यान्वयन के साथ एक निकालने वाला होता है। मुझे आशा है कि इससे मदद मिलेगी।

+1

अच्छा जवाब, लेकिन कृपया कई टाइपो के लिए इसे एक बार फिर से ऊपर जाएं। धन्यवाद! –

+0

इस उत्तर के लिए आपको बहुत बहुत धन्यवाद, मुझे नहीं पता था कि केस संशोधक के विपरीत सीलबंद पदानुक्रमों के माध्यम से थकावट हासिल की जाती है। हालांकि अगर मैं प्रकारों से मिलान करने से परे पैटर्न मिलान को बढ़ाता हूं (मैंने मूल सुधार में यह सुधार जोड़ा है) मुझे अभी भी अप्रत्याशित व्यवहार मिलता है, जो, जैसा कि यह निकलता है, संकलक संस्करण पर निर्भर करता है :( –

2

सामान्यतः, यह नहीं किया जा सकता है।

मुहरबंद कक्षाएं एक विशेष मामला हैं (कोई इरादा नहीं है) क्योंकि scalac संकलित समय में कितने मैचों संभव हैं, जानता है।

लेकिन चूंकि निकालने वाले आपको मनमाने ढंग से कोड चलाने की अनुमति देते हैं और हानिकारक रोकथाम की समस्या के कारण, प्रत्येक मामले में संकलक को गारंटी देने का कोई तरीका नहीं है कि आप हर मामले की जांच करेंगे। पर विचार करें:

def test(foo: Int) { 
    foo match { 
    case IsMultipleOf8(n) => printf("%d was odd\n", n) 
    } 
} 

यह संपूर्ण क्योंकि यह संख्या 8 के गुणकों नहीं हैं संभाल नहीं है नहीं है, लेकिन संकलक (सभी Int की पर अपने निकालने चलने के बिना) अनुमान नहीं कर सकता है कि केवल प्रकार के कुछ मान Int 8. के ​​गुणक हैं

+1

हां, सामान्य रूप से सामान्य मामले में यह सच है। हालांकि मेरे उदाहरण में एक्स्ट्रेक्टर ऑब्जेक्ट हमेशा कुछ देता है (क्योंकि इसका रिटर्न टाइप कुछ [Int] है और कोई बूलियन या विकल्प नहीं है), इसलिए यह गारंटी है कि मिलान विफल नहीं हो सकता है (यानी अगर अनजाने विधि अंततः टर्मिनेट्स, जो मुझे लगता है कि एक उचित धारणा है)। इसलिए केवल एक चीज जिसे जांचने की आवश्यकता है वह यह है कि पदानुक्रम से सभी प्रकार शामिल हैं। ध्यान दें कि कंपाइलर निश्चित रूप से मिलान किए जाने वाले मान (प्रकार के नोड) को कास्ट करने में सक्षम है कंक्रीट प्रकार निकालने वाले द्वारा स्वीकार किया जाता है, इसलिए यह पदानुक्रम से अवगत है। –