2011-08-08 10 views
33

मैं एक श्रेणी पदानुक्रम तैयार कर रहा हूं, जिसमें कई लक्षणों के साथ बेस क्लास शामिल है। बेस क्लास कई विधियों के डिफ़ॉल्ट कार्यान्वयन प्रदान करता है, और गुण abstract override के माध्यम से कुछ तरीकों को चुनिंदा रूप से ओवरराइड करते हैं, ताकि स्टैकेबल गुण/मिश्रण के रूप में कार्य किया जा सके।अंतर्निहित "कन्स्ट्रक्टर पैरामीटर" के रूप में लक्षणों की घोषणा कैसे करें?

एक डिजाइन परिप्रेक्ष्य यह अच्छी तरह से काम करता है, और डोमेन के लिए नक्शे से इतना है कि मैं मैं यहाँ से (एक विशेषता) आदि एक विधेय यहां से (एक और विशेषता)

के साथ एक छानने समारोह में जोड़ सकते हैं हालांकि, अब निहित मानकों को लेने के लिए मेरे कुछ लक्षणों की तरह है। मुझे खुशी है कि यह अभी भी एक डिजाइन परिप्रेक्ष्य से समझ में आता है, और अभ्यास में भ्रमित साबित नहीं होगा। हालांकि, मैं इसके साथ चलाने के लिए संकलक को मनाने के लिए मना नहीं कर सकता।

समस्या का मूल यह प्रतीत होता है कि मैं एक विशेषता के लिए कन्स्ट्रक्टर तर्क प्रदान नहीं कर सकता, जैसे कि उन्हें अंतर्निहित चिह्नित किया जा सकता है। एक विधि कार्यान्वयन के भीतर अंतर्निहित पैरामीटर का संदर्भ अपेक्षित "अनुमानित मूल्य नहीं मिला" संदेश के साथ संकलित करने में विफल रहता है; मैं के माध्यम से

implicit val e = implicitly[ClassName] 

विधि के भीतर उपलब्ध होने के "प्रचार" करने के लिए निर्माण मंच (जहां, व्यवहार में, यह दायरे में हमेशा) से निहित कोशिश की, लेकिन (कोई संदेह नहीं है के रूप में आप में से कई की उम्मीद) कि परिभाषा एक ही संदेश के साथ विफल रहा।

ऐसा लगता है कि समस्या यह है कि मैं implicit ClassName ध्वज के साथ विशेषता के हस्ताक्षर को टैग करने के लिए संकलक को मनाने के लिए संकलित नहीं कर सकता, और निहित प्रदान करने के लिए कॉलर्स (यानी जो वस्तु को गुण में मिलाते हैं) । वर्तमान में मेरे कॉलर ऐसा कर रहे हैं, लेकिन संकलक इस स्तर पर जांच नहीं कर रहा है।


वहाँ किसी भी तरह से कुछ implicits निर्माण समय पर उपलब्ध हो की आवश्यकता होती है के रूप में एक विशेषता चिह्नित करने के लिए है?

उत्तर

15

वास्तव में (और अगर नहीं, तो इस बस अभी तक लागू नहीं है या वहाँ एक गहरी कारण है कि यह अव्यावहारिक है?), मैं इस चाहता था अक्सर से पहले, लेकिन सिर्फ इस विचार के साथ आया था । आप अनुवाद कर सकते हैं

trait T(implicit impl: ClassName) { 
    def foo = ... // using impl here 
} 
को

[संपादित: मूल संस्करण अन्य तरीकों के लिए अंतर्निहित के लिए उपयोग नहीं प्रदान की थी]

trait T { 
    // no need to ever use it outside T 
    protected case class ClassNameW(implicit val wrapped: ClassName) 

    // normally defined by caller as val implWrap = ClassNameW 
    protected val implWrap: ClassNameW 

    // will have to repeat this when you extend T and need access to the implicit 
    import implWrap.wrapped 

    def foo = ... // using wrapped here 
} 
+0

क्या कॉलर स्पष्ट रूप से अज्ञात वस्तु में 'implWrap' को परिभाषित नहीं करता है, क्योंकि यह विशेषता में एक सार क्षेत्र है? (यदि नहीं, तो मुझे समझ में नहीं आता कि यह कैसे सेट किया गया है; क्या आप समझाएंगे?) –

+0

हां, लेकिन टिप्पणी देखें: यदि वह अंतर्निहित उपयोग करना चाहता है, तो वह केवल 'वैल इंप्रास्ट्रैप = ​​क्लासनाम' लिख सकता है। मुझे ऐसा करने का एक अच्छा तरीका नहीं दिख रहा है: जैसा कि आप इस प्रश्न में उल्लेख करते हैं, लक्षणों में _any_ कन्स्ट्रक्टर पैरामीटर नहीं हैं (जिन्हें अंतर्निहित चिह्नित किया जा सकता है)। –

+7

बेशक, मैं एक बेहतर समाधान देखने में बहुत खुश हूं। –

0

आप इस तरह यह कर सकता है:

abstract class C 

trait A { this: C => 
    val i: Int 
}  

implicit val n = 3 

val a = new C with A { 
    val i = implicitly[Int] 
} 

लेकिन मैं मुझे यकीन नहीं है कि इसमें कोई बात है या नहीं - आप स्पष्ट रूप से अंतर्निहित मूल्य को भी संदर्भित कर सकते हैं।

मुझे लगता है कि आप तत्काल में i के कार्यान्वयन से छुटकारा पाने के लिए क्या चाहते हैं, लेकिन जैसा कि आप स्वयं कहते हैं, समस्या का मूल यह है कि लक्षण रचनाकार मानकों को नहीं लेते हैं - चाहे वे निहित हों या नहीं कोई फर्क नहीं पड़ता।

इस समस्या के लिए सम्भावित समाधान पहले से ही मान्य सिंटैक्स के लिए एक नई सुविधा जोड़ने के लिए होगा:

trait A { 
    implicit val i: Int 
} 

जहां i संकलक द्वारा लागू किया जाएगा एक अंतर्निहित दायरे में था।

11

मैं इस समस्या में कुछ बार भाग गया, और वास्तव में यह थोड़ा परेशान है, लेकिन बहुत अधिक नहीं है। सार सदस्यों और पैरामीटर आमतौर पर एक ही चीज करने के दो वैकल्पिक तरीके होते हैं, उनके फायदे और नुकसान के साथ; एक अमूर्त सदस्य होने वाले गुणों के लिए बहुत असुविधाजनक नहीं है, क्योंकि आपको किसी भी प्रकार की विशेषता को लागू करने के लिए किसी भी वर्ग की आवश्यकता है। *

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

trait Base[T] { 
    val numT: Ordering[T] 
} 
/* Here we use a context bound, thus cannot specify the name of the implicit 
* and must define the field explicitly. 
*/ 
class Der1[T: Ordering] extends Base[T] { 
    val numT = implicitly[Ordering[T]] 
    //Type inference cannot figure out the type parameter of implicitly in the previous line 
} 
/* Here we specify an implicit parameter, but add val, so that it automatically 
* implements the abstract value of the superclass. 
*/ 
class Der2[T](implicit val numT: Ordering[T]) extends Base[T] 

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

* यही कारण नहीं है कि विशेषता पैरामीटर स्वीकार नहीं कर सकती - मुझे यह नहीं पता। मैं सिर्फ बहस कर रहा हूं कि इस मामले में सीमा स्वीकार्य है।

+2

हालांकि, इस तरह आपके पास 'आधार [टी] 'में विधियों को परिभाषित करते समय एक अंतर्निहित' ऑर्डरिंग [टी]' तक पहुंच नहीं है। और यदि आप 'numT' अंतर्निहित करते हैं, तो आप _this_ समस्या को ठीक करते हैं, लेकिन' वैल numT = implicitly [ऑर्डरिंग [टी]] 'एक अनंत लूप बन जाता है। –

+1

यदि आप इस समस्या को हल करने के लिए 'बेस' को संशोधित करते हैं, तो आप Der1 नहीं लिख सकते हैं, लेकिन Der2 वैसे भी काम करता है - और समकक्ष होने पर भी Der1 से अधिक कॉम्पैक्ट है। 'विशेषता आधार [टी] { निहित वैल संख्या: ऑर्डरिंग [टी] } कक्षा डेर 2 [टी] (निहित वैल संख्या: ऑर्डरिंग [टी]) आधार [टी]' – Blaisorblade

0

जैसा कि ऐसा लगता है कि यह संभव नहीं है, मैं मूल श्रेणी के निर्माता पर अंतर्निहित val घोषित करने के विकल्प के लिए गया था। जैसा कि इस सवाल में बताया गया है कि यह आदर्श नहीं है, लेकिन यह संकलक को संतुष्ट करता है और व्यावहारिक रूप से, मेरे विशेष मामले में बोझ का अधिक नहीं है।

यदि किसी के पास कोई बेहतर समाधान है, तो मुझे यह सुनकर खुशी होगी।

7

यह संभव नहीं है।

लेकिन आप implicitly और स्कैला के प्रकार अनुमान को जितना संभव हो सके दर्द रहित बनाने के लिए उपयोग कर सकते हैं।

trait MyTrait { 

    protected[this] implicit def e: ClassName 

} 

और फिर

class MyClass extends MyTrait { 

    protected[this] val e = implicitly // or def 

} 

संक्षिप्त, और यहां तक ​​विस्तार कक्षा में प्रकार लेखन की आवश्यकता नहीं है।

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