2010-12-07 11 views
15

नोट: मैं यह प्रश्न स्वयं उत्तर देने के लिए प्रस्तुत कर रहा हूं, लेकिन अन्य उत्तरों का स्वागत है।मैं संदर्भ संदर्भ से जुड़े प्रकार वर्ग का उदाहरण कैसे प्राप्त करूं?

निम्नलिखित सरल विधि पर विचार करें:

def add[T](x: T, y: T)(implicit num: Numeric[T]) = num.plus(x,y) 

मैं इस एक context bound का उपयोग कर के रूप में

def add[T: Numeric](x: T, y: T) = ??.plus(x,y) 

इस प्रकार पुनर्लेखन सकते हैं, लेकिन इतना है कि मैं आह्वान कर सकते हैं कि कैसे मैं Numeric[T] प्रकार का एक उदाहरण मिलता है plus विधि?

उत्तर

23

परोक्ष विधि

सबसे आम और सामान्य दृष्टिकोण implicitly method, Predef में परिभाषित उपयोग करने के लिए है का उपयोग करना:

def add[T: Numeric](x: T, y: T) = implicitly[Numeric[T]].plus(x,y) 

जाहिर है, यह कुछ हद तक वर्बोज़ है और नाम दोहराने की आवश्यकता है प्रकार वर्ग के।

def add[T: Numeric](x: T, y: T) = evidence$1.plus(x,y) 

ऐसा नहीं है कि आश्चर्य की बात है:

सबूत पैरामीटर (! नहीं)

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

प्रसंग (शुरू context विधि)

इसके बजाय, एक implicitly विधि का एक तगड़ा बनाया अप संस्करण का उपयोग कर सकते हैं। ध्यान दें कि परोक्ष तरीके के रूप में

def implicitly[T](implicit e: T): T = e 

इस विधि बस विधि कॉल में आसपास के दायरे से सही प्रकार की एक अंतर्निहित ऑब्जेक्ट सम्मिलित करने संकलक पर निर्भर करता है, और फिर इसे वापस आती है परिभाषित किया गया है। हम थोड़ा बेहतर कर सकते हैं:

def context[C[_], T](implicit e: C[T]) = e 

यह हमें के रूप में

def add[T: Numeric](x: T, y: T) = context.plus(x,y) 

context विधि प्रकार पैरामीटर Numeric और T हमारे add विधि को परिभाषित करने के दायरे पर आधारित हैं अनुमति देता है! दुर्भाग्य से, ऐसी परिस्थितियां हैं जिनमें यह context विधि काम नहीं करेगी। जब एक प्रकार पैरामीटर में एकाधिक संदर्भ सीमाएं होती हैं या उदाहरण के लिए विभिन्न संदर्भ सीमाओं के साथ कई पैरामीटर होते हैं।हम एक से थोड़ा अधिक जटिल संस्करण के साथ बाद समस्या का समाधान कर सकते हैं:

class Context[T] { def apply[C[_]]()(implicit e: C[T]) = e } 
def context[T] = new Context[T] 

इस संस्करण प्रकार पैरामीटर हर बार निर्दिष्ट करने के लिए हमें आवश्यकता है, लेकिन कई प्रकार पैरामीटर संभालती है।

def add[T: Numeric](x: T, y: T) = context[T]().plus(x,y) 
+5

'संदर्भ' विधि के साथ चालाक हैक! –

+8

लड़का, अगर मैंने सोचा कि कोई सबूत पैरामीटर के नाम पर निर्भर था जिस तरह से मैं इसे सप्ताह में एक बार बदलता हूं ... भी, तकनीक मेरे क्षेत्राधिकार में कानूनी नहीं है, लेकिन शायद कानून अलग हैं जहां आप अलग हैं जीना। – extempore

+0

वास्तव में बहुत चालाक। – pedrofurla

7

कम से कम स्काला 2.9 के बाद से आप निम्न कर सकते हैं:

import Numeric.Implicits._ 
def add[T: Numeric](x: T, y: T) = x + y 

add(2.8, 0.1) // res1: Double = 2.9 
add(1, 2) // res2: Int = 3 
+0

धन्यवाद, यह दस्तावेज़ों से कभी स्पष्ट नहीं था कि यह कैसे काम करता है! – Lachlan

4

इस उत्तर एक और दृष्टिकोण है कि अधिक पठनीय, स्वयं का दस्तावेजीकरण ग्राहक कोड में परिणाम है वर्णन करता है।

प्रेरणा

context method that I described previously एक बहुत ही सामान्य समाधान है कि किसी भी प्रकार के वर्ग के साथ काम करता है, किसी अतिरिक्त प्रयास के बिना है। हालांकि, यह दो कारणों के लिए अवांछनीय हो सकता है:

  • context विधि जब प्रकार पैरामीटर के बाद से संकलक जो संदर्भ के लिए बाध्य करना है निर्धारित करने के लिए कोई तरीका नहीं है, कई संदर्भ सीमा है नहीं किया जा सकता।

  • जेनेरिक context विधि का संदर्भ क्लाइंट कोड की पठनीयता को नुकसान पहुंचाता है।

प्रकार स्तरीय विशेष तरीकों

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

// definition in Predef 
def manifest[T](implicit m: Manifest[T]) = m 

// example usage 
def getErasure[T: Manifest](x: T) = manifest[T].erasure 

इस दृष्टिकोण सामान्यीकरण

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

class Implicitly[TC[_]] { def apply[T]()(implicit e: TC[T]) = e } 
object Implicitly { def apply[TC[_]] = new Implicitly[TC] } 

फिर एक नए प्रकार स्तरीय विशेष परोक्ष शैली विधि परिभाषित किया जा सकता,: हम निम्नलिखित परिभाषा के साथ इस प्रक्रिया को कम कर सकते हैं

def numeric = Implicitly[Numeric] 
// or 
val numeric = Implicitly[Numeric] 

अंत में, ग्राहक कोड कर सकते हैं निम्नानुसार लागू करें:

def add[T: Numeric](x: T, y: T) = numeric[T].plus(x, y) 
संबंधित मुद्दे