2011-09-30 10 views
8

मैं यह पता लगाने की एक स्काला सार प्रकार के लिए एक निर्माता को लागू करने की कोशिश कर रहा हूँ कैसे:मैं स्कैला अमूर्त प्रकार के निर्माता को कैसे बुला सकता हूं?

class Journey(val length: Int) 
class PlaneJourney(length: Int) extends Journey(length) 
class BoatJourney(length: Int) extends Journey(length) 

class Port[J <: Journey] { 
    def startJourney: J = { 
    new J(23) // error: class type required but J found 
    } 
} 

यह और भी संभव है? मैं Scala manifests से परिचित हूं लेकिन मुझे स्पष्ट नहीं है कि वे यहां कैसे मदद कर सकते हैं। इसी तरह मैं समझ नहीं कैसे एक साथी के साथ भी ऐसा ही करने पर आपत्ति की लागू() निर्माता:

object Journey { def apply() = new Journey(0) } 
object PlaneJourney { def apply() = new PlaneJourney(0) } 
object BoatJourney { def apply() = new BoatJourney(0) } 

class Port[J <: Journey] { 
    def startJourney: J = { 
    J() // error: not found: value J 
    } 
} 

किसी भी विचारों कृतज्ञता प्राप्त!

उत्तर

7

कन्स्ट्रक्टर का आह्वान करने या केवल एक प्रकार के साथी ऑब्जेक्ट तक पहुंचने का कोई सीधा तरीका नहीं है। एक समाधान एक प्रकार की कक्षा का उपयोग करना होगा जो दिए गए प्रकार का डिफ़ॉल्ट उदाहरण बनाता है।

trait Default[A] { def default: A } 

class Journey(val length: Int) 
object Journey { 
    // Provide the implicit in the companion 
    implicit def default: Default[Journey] = new Default[Journey] { 
    def default = new Journey(0) 
    } 
} 

class Port[J <: Journey : Default] { 
    // use the Default[J] instance to create the instance 
    def startJourney: J = implicitly[Default[J]].default 
} 

आप कक्षाओं के सभी साथी वस्तुओं है कि एक डिफ़ॉल्ट उदाहरण के निर्माण का समर्थन करने के एक अंतर्निहित Default परिभाषा जोड़ने की आवश्यकता होगी।

+0

धन्यवाद मोरित्ज़ - लेकिन आरईपीएल में आपके कोड को चिपकाने से कुछ त्रुटियां फेंकता है? मैं डिफ़ॉल्ट "कन्स्ट्रक्टर" में पैरामीटर कैसे जोड़ूं? –

+0

आपको इस कोड के लिए आरईपीएल में काम करने के लिए पेस्ट मोड दर्ज करना होगा (पेस्ट करने से पहले बस 'पेस्ट' टाइप करें)। फिलिप द्वारा तय किए गए कोड में भी एक त्रुटि हुई थी। – Moritz

+1

यदि आप पैरामीटर जोड़ना चाहते हैं तो आप 'डिफ़ॉल्ट' विशेषता में बस एक नई विधि जोड़ सकते हैं। 'निस्संदेह [डिफ़ॉल्ट [जे]] 'आपको आपूर्ति प्रकार के पैरामीटर के साथ विशेषता का एक उदाहरण देगा और आप जिस पर चाहें उसे किसी भी विधि का आह्वान कर सकते हैं, उदा। 'परोक्ष [डिफ़ॉल्ट [जम्मू]]। (23) बनाने के'। उदाहरण के लिए देखें [यह प्रश्न] (http://stackoverflow.com/questions/5598085/where-does-scala-look-for-implicits) अंतर्निहित कार्यों के विवरण के विवरण के लिए देखें। – Moritz

0

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

  1. आप एक प्रकार तर्क टी के साथ एक वर्ग पोर्ट है जहां टी यात्रा से विरासत चाहिए (लेकिन टी बिल्कुल यात्रा, इस होना करने के लिए नहीं है महत्वपूर्ण है)।
  2. पोर्ट के भीतर, आप एक विधि को परिभाषित करते हैं जो एक नया टी बनाता है। इस वर्ग को पता नहीं है कि टी क्या है, और इसलिए टी का कन्स्ट्रक्टर कैसा दिखता है।
  3. क्योंकि आप नहीं जानते कि टी के निर्माता क्या तर्क लेते हैं, आप नहीं जानते कि इसके पास कौन से तर्क पास हैं।

इस समस्या का समाधान एक और सवाल में बहुत अच्छी तरह से नियंत्रित किया जाता है, इसलिए मैं नहीं बल्कि यहां दोहरा से उनके लिए वहाँ बताएगा: Abstract Types/Type Parameters in Scala

7

आपका वर्ग Manifest प्राप्त करने के लिए एक अंतर्निहित निर्माता पैरामीटर की जरूरत है। फिर आप Class प्राप्त करने के लिए मिटा सकते हैं और newInstance पर कॉल कर सकते हैं, जो कि अगर कोई है तो नुकीली कन्स्ट्रक्टर को प्रतिबिंबित करता है।

class J[A](implicit m:Manifest[A]) { 
    def n = m.erasure.newInstance() 
} 

new J[Object].n 

स्काला 2.10 के रूप में, प्रकट में erasure संपत्ति मान्य नहीं है। def n = m.runtimeClass.newInstance() वही काम करता है, लेकिन चेतावनियों के बिना।

+0

क्या इस दृष्टिकोण को पैरामीटर रहित कन्स्ट्रक्टर की आवश्यकता नहीं है? –

+0

@ क्रिस यह करता है, और यह सीमा है। जब तक आप किसी भी कारखाने की आवश्यकता नहीं होती है। –

+0

धन्यवाद किम - नया इंस्टेंस() "कन्स्ट्रक्टर" स्पष्ट रूप से समझाया गया है –

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