2015-11-05 10 views
9

में उपयोग किए जाने वाले 'लोप्रोरिटीइम्पलिट्स' पैटर्न को समझाएं, कुछ स्कैला पुस्तकालयों के स्रोत को देखते समय, उदा। shapeless, मुझे अक्सर LowPriorityImplicits नामक लक्षण मिलते हैं।स्कैला प्रकार-स्तरीय प्रोग्रामिंग

क्या आप इस पैटर्न को समझा सकते हैं? हल की गई समस्या क्या है, और पैटर्न इसे कैसे हल करता है?

उत्तर

13

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

trait MyTypeclass[T] { def foo: String } 
object MyTypeclass { 
    implicit def anyCanBeMyTC[T]: MyTypeclass[T] = new MyTypeclass[T] { 
    val foo = "any" 
    } 

    implicit def specialForString[T](implicit ev: T <:< String): MyTypeclass[T] = new MyTypeclass[T] { 
    val foo = "string" 
    } 
} 

println(implicitly[MyTypeclass[Int]].foo) // Prints "any" 
println(implicitly[MyTypeclass[Boolean]].foo) // Prints "any" 
println(implicitly[MyTypeclass[String]].foo) // Compilation error 

त्रुटि आप अंतिम पंक्ति में मिलता है: एक उदाहरण के रूप निम्नलिखित पर विचार

<console>:25: error: ambiguous implicit values: 
    both method anyCanBeMyTC in object MyTypeclass of type [T]=> MyTypeclass[T] 
    and method specialForString in object MyTypeclass of type [T](implicit ev: <: <[T,String])MyTypeclass[T] 
    match expected type MyTypeclass[String] 
     println(implicitly[MyTypeclass[String]].foo) 

यह संकलन नहीं करेंगे क्योंकि निहित संकल्प अस्पष्टता मिलेगा; इस मामले में यह थोड़ा कृत्रिम है कि हम String मामले को अस्पष्टता को ट्रिगर करने के लिए अंतर्निहित साक्ष्य का उपयोग कर परिभाषित कर रहे हैं जब हम इसे implicit def specialForString: MyTypeclass[String] = ... के रूप में परिभाषित कर सकते हैं और कोई अस्पष्टता नहीं है।

trait MyTypeclass[T] { def foo: String } 

trait LowPriorityInstances { 
    implicit def anyCanBeMyTC[T]: MyTypeclass[T] = new MyTypeclass[T] { 
    val foo = "any" 
    } 
} 

object MyTypeclass extends LowPriorityInstances { 
    implicit def specialForString[T](implicit ev: T <:< String): MyTypeclass[T] = new MyTypeclass[T] { 
    val foo = "string" 
    } 
} 

println(implicitly[MyTypeclass[Int]].foo) // Prints "any" 
println(implicitly[MyTypeclass[Boolean]].foo) // Prints "any" 
println(implicitly[MyTypeclass[String]].foo) // Prints "string" 

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

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