इंप्लिकिट्स के प्रकार
स्काला में इंप्लिसिट्स या तो एक मान को संदर्भित करता है जिसे "स्वचालित रूप से" पारित किया जा सकता है, इसलिए बोलने के लिए, या एक प्रकार से दूसरे में रूपांतरण जो स्वचालित रूप से बनाया गया है।
अव्यवस्थित रूपांतरण
, उत्तरार्द्ध प्रकार के बारे में बहुत संक्षेप में बात हो रही है अगर एक एक विधि कॉल m
एक वस्तु पर o
एक वर्ग के C
हैं, और उस वर्ग नहीं है समर्थन विधि m
, तो स्काला से एक अंतर्निहित रूपांतरण के लिए दिखेगा C
कुछ ऐसा है जो करने के लिए करता है समर्थन m
। एक सरल उदाहरण इस पद्धति map
पर होगा String
:
"abc".map(_.toInt)
String
विधि का समर्थन नहीं करता map
है, लेकिन StringOps
करता है, और वहाँ से एक अंतर्निहित रूपांतरण है String
करने के लिए StringOps
उपलब्ध है (देखें implicit def augmentString
पर Predef
)।
निहित पैरामीटर
अन्य प्रकार का निहितार्थ निहित पैरामीटर है । इन्हें किसी अन्य पैरामीटर की तरह कॉल करने के लिए पास किया जाता है, लेकिन कंपाइलर इन्हें अपने आप भरने की कोशिश करता है। यदि ऐसा नहीं हो सकता है, तो यह शिकायत करेगा। कोई भी इन मापदंडों को स्पष्ट रूप से पारित कर सकता है , जो कि एक का उपयोग करता है breakOut
, उदाहरण के लिए ( breakOut
एक प्रश्न के बारे में सवाल देखें , जिस दिन आप एक चुनौती के लिए महसूस कर रहे हैं)।
इस मामले में, किसी को निहित की आवश्यकता की घोषणा करनी होगी, जैसे कि foo
विधि घोषणा:
def foo[T](t: T)(implicit integral: Integral[T]) {println(integral)}
सीमा देखें
एक स्थिति है जहां एक निहितार्थ एक अंतर्निहित रूपांतरण और एक अंतर्निहित पैरामीटर दोनों है। उदाहरण के लिए:
def getIndex[T, CC](seq: CC, value: T)(implicit conv: CC => Seq[T]) = seq.indexOf(value)
getIndex("abc", 'a')
विधि getIndex
किसी भी वस्तु को प्राप्त कर सकती है, जब तक कि उसके वर्ग से एक अंतर्निहित रूपांतरण उपलब्ध है Seq[T]
। इस कारण से, मैं एक पारित कर सकते हैं String
करने के लिए getIndex
है, और यह काम करेंगे।
दृश्यों के पीछे, संकलक में परिवर्तन seq.IndexOf(value)
होता है conv(seq).indexOf(value)
।
यह इतना उपयोगी है कि उन्हें लिखने के लिए वाक्य रचना चीनी है। इस प्रकार से बनाई जाने वाली चीनी का उपयोग करके इसे इस getIndex
तरह परिभाषित किया जा सकता है:
def getIndex[T, CC <% Seq[T]](seq: CC, value: T) = seq.indexOf(value)
इस सिनटैक्ट शुगर को व्यू बाउंड , एक अपर बाउंड ( CC <: Seq[Int]
) या लोअर बाउंड ( T >: Null
) के समान बताया गया है।
प्रसंग सीमा
निहित मापदंडों में एक और सामान्य पैटर्न प्रकार वर्ग पैटर्न है । यह पैटर्न उन वर्गों के लिए सामान्य इंटरफेस के प्रावधान को सक्षम करता है जो उन्हें घोषित नहीं करते थे। यह दोनों एक पुल पैटर्न के रूप में सेवा कर सकता है - चिंताओं को अलग करना - और एक एडाप्टर पैटर्न के रूप में।
जिस Integral
कक्षा का आपने उल्लेख किया है वह टाइप क्लास पैटर्न का एक उत्कृष्ट उदाहरण है। स्काला के मानक पुस्तकालय पर एक और उदाहरण है Ordering
। एक पुस्तकालय है जो इस पैटर्न का भारी उपयोग करता है, जिसे स्कलाज़ कहा जाता है।
यह इसके उपयोग का एक उदाहरण है:
def sum[T](list: List[T])(implicit integral: Integral[T]): T = {
import integral._ // get the implicits in question into scope
list.foldLeft(integral.zero)(_ + _)
}
इसके लिए सिंटैक्टिक शुगर भी है, जिसे एक संदर्भ बाउंड कहा जाता है, जिसे निहितार्थ को संदर्भित करने की आवश्यकता से कम उपयोगी बनाया जाता है। इस पद्धति का एक सीधा रूपांतरण इस तरह दिखता है:
def sum[T : Integral](list: List[T]): T = {
val integral = implicitly[Integral[T]]
import integral._ // get the implicits in question into scope
list.foldLeft(integral.zero)(_ + _)
}
संदर्भ सीमाएं तब अधिक उपयोगी होती हैं जब आपको उन्हें अन्य तरीकों से पास करने की आवश्यकता होती है जो उनका उपयोग करते हैं। उदाहरण के लिए, विधि sorted
पर Seq
एक निहित की जरूरत है Ordering
। एक विधि बनाने के लिए reverseSort
, कोई लिख सकता है:
def reverseSort[T : Ordering](seq: Seq[T]) = seq.sorted.reverse
क्योंकि Ordering[T]
अंतर्निहित रूप से reverseSort
इसे पारित किया गया था , इसलिए यह इसे अंतर्निहित रूप से पारित कर सकता है sorted
।
इंप्लिकिट कहाँ से आते हैं?
जब कंपाइलर एक निहित की आवश्यकता को देखता है, या तो क्योंकि आप एक ऐसी विधि को बुला रहे हैं जो ऑब्जेक्ट की कक्षा में मौजूद नहीं है, या क्योंकि आप एक ऐसी विधि को बुला रहे हैं जिसके लिए एक अंतर्निहित पैरामीटर की आवश्यकता होती है, यह एक अंतर्निहित की खोज करेगा जो आवश्यकता को फिट करेगा ।
यह खोज कुछ नियमों का पालन करती है जो परिभाषित करते हैं कि कौन से निहितार्थ दिखाई देते हैं और जो नहीं हैं। निम्न तालिका यह दिखाती है कि कंपाइलर इम्पीचिट्स की खोज करेगा, जोश सुरेथ द्वारा इम्पीकिट्स के बारे में एक उत्कृष्ट प्रस्तुति से लिया गया था , जिसे मैं दिल से किसी को भी अपने स्काला ज्ञान में सुधार करने की सलाह देता हूं। यह तब से पूरक है जब प्रतिक्रिया और अपडेट के साथ।
नीचे दिए गए नंबर 1 के तहत उपलब्ध निहितार्थों में संख्या 2 के तहत पूर्ववर्तीता है। इसके अलावा, यदि कई योग्य तर्क हैं जो अंतर्निहित पैरामीटर के प्रकार से मेल खाते हैं, तो एक सबसे विशिष्ट को स्थिर ओवरलोडिंग रिज़ॉल्यूशन के नियमों का उपयोग करके चुना जाएगा (देखें स्काला) विशिष्टता §6.26.3)। इस उत्तर के अंत में एक प्रश्न I लिंक से अधिक विस्तृत जानकारी मिल सकती है।
- पहले वर्तमान दायरे में देखें
- वर्तमान स्कोप में परिभाषित इम्प्लाइक
- आयात आयात करें
- वाइल्डकार्ड आयात
अन्य फ़ाइलों में समान गुंजाइश
- अब इसमें जुड़े प्रकारों को देखें
- एक प्रकार की साथी वस्तुएँ
- किसी तर्क के प्रकार का अनुमानित दायरा (2.9.1)
- प्रकार के तर्कों का निहित दायरा (2.8.0)
- नेस्टेड प्रकारों के लिए बाहरी वस्तुएं
- अन्य आयाम
आइए उनके लिए कुछ उदाहरण दें:
करंट स्कोप को वर्तमान स्कोप में परिभाषित किया गया
implicit val n: Int = 5
def add(x: Int)(implicit y: Int) = x + y
add(5) // takes n from the current scope
स्पष्ट आयात
import scala.collection.JavaConversions.mapAsScalaMap
def env = System.getenv() // Java map
val term = env("TERM") // implicit conversion from Java Map to Scala Map
वाइल्डकार्ड आयात
def sum[T : Integral](list: List[T]): T = {
val integral = implicitly[Integral[T]]
import integral._ // get the implicits in question into scope
list.foldLeft(integral.zero)(_ + _)
}
अन्य फ़ाइलों में समान स्कोप
संपादित करें : ऐसा लगता है कि इसकी एक अलग मिसाल नहीं है। यदि आपके पास कुछ उदाहरण हैं जो एक पूर्ववर्ती भेद को प्रदर्शित करता है, तो कृपया एक टिप्पणी करें। अन्यथा, इस पर भरोसा मत करो।
यह पहले उदाहरण की तरह है, लेकिन अनुमान लगाने की परिभाषा इसके उपयोग की तुलना में एक अलग फ़ाइल में है। यह भी देखें कि कैसे आरेख में लाने के लिए पैकेज ऑब्जेक्ट का उपयोग किया जा सकता है।
एक प्रकार की साथी वस्तुएँ
यहां नोट के दो ऑब्जेक्ट साथी हैं। सबसे पहले, "स्रोत" प्रकार के ऑब्जेक्ट साथी पर ध्यान दिया जाता है। उदाहरण के लिए, ऑब्जेक्ट के अंदर Option
एक अंतर्निहित रूपांतरण होता है Iterable
, इसलिए कोई उन Iterable
तरीकों को कॉल कर सकता है Option
, या Option
किसी से अपेक्षा कर सकता है Iterable
। उदाहरण के लिए:
for {
x <- List(1, 2, 3)
y <- Some('x')
} yield (x, y)
उस अभिव्यक्ति को संकलक द्वारा अनुवादित किया जाता है
List(1, 2, 3).flatMap(x => Some('x').map(y => (x, y)))
हालांकि, List.flatMap
एक की उम्मीद है TraversableOnce
, जो Option
नहीं है। संकलक तब Option
वस्तु के साथी को देखता है और रूपांतरण को पाता है Iterable
, जो कि एक है TraversableOnce
, जिससे यह अभिव्यक्ति सही हो जाती है।
दूसरा, अपेक्षित प्रकार के साथी वस्तु:
List(1, 2, 3).sorted
विधि sorted
एक निहित लेता है Ordering
। इस मामले में, यह ऑब्जेक्ट के अंदर दिखता है Ordering
, वर्ग के साथी Ordering
, और वहां एक निहित पाता है Ordering[Int]
।
ध्यान दें कि सुपर क्लास की साथी वस्तुओं को भी देखा जाता है। उदाहरण के लिए:
class A(val n: Int)
object A {
implicit def str(a: A) = "A: %d" format a.n
}
class B(val x: Int, y: Int) extends A(y)
val b = new B(5, 2)
val s: String = b // s == "A: 2"
इस तरह से स्काला ने निहित Numeric[Int]
और Numeric[Long]
आपके प्रश्न में, वैसे पाया, जैसे वे अंदर पाए जाते हैं Numeric
, नहीं Integral
।
एक तर्क के प्रकार का स्पष्ट स्कोप
यदि आपके पास एक तर्क प्रकार के साथ एक विधि है A
, तो प्रकार के अंतर्निहित दायरे पर A
भी विचार किया जाएगा। "निहित गुंजाइश" से मेरा मतलब है कि इन सभी नियमों को पुनरावर्ती रूप से लागू किया जाएगा - उदाहरण के लिए, A
उपर्युक्त नियम के अनुसार , के साथी ऑब्जेक्ट को खोज के लिए खोजा जाएगा।
ध्यान दें कि इसका मतलब यह नहीं है A
कि उस पैरामीटर के रूपांतरणों के लिए निहित गुंजाइश की खोज की जाएगी, बल्कि संपूर्ण अभिव्यक्ति की। उदाहरण के लिए:
class A(val n: Int) {
def +(other: A) = new A(n + other.n)
}
object A {
implicit def fromInt(n: Int) = new A(n)
}
// This becomes possible:
1 + new A(1)
// because it is converted into this:
A.fromInt(1) + new A(1)
यह स्काला 2.9.1 के बाद से उपलब्ध है।
टाइप आर्ग्युमेंट्स का इंप्लांट स्कोप
टाइप क्लास पैटर्न को वास्तव में काम करने के लिए यह आवश्यक है। Ordering
उदाहरण के लिए विचार करें : यह अपने साथी ऑब्जेक्ट में कुछ इम्पिटिट के साथ आता है, लेकिन आप इसमें सामान नहीं जोड़ सकते। तो आप Ordering
अपने वर्ग के लिए कैसे बना सकते हैं जो स्वचालित रूप से पाया जाता है?
आइए कार्यान्वयन के साथ शुरू करें:
class A(val n: Int)
object A {
implicit val ord = new Ordering[A] {
def compare(x: A, y: A) = implicitly[Ordering[Int]].compare(x.n, y.n)
}
}
इसलिए, विचार करें कि जब आप कॉल करते हैं तो क्या होता है
List(new A(5), new A(2)).sorted
जैसा कि हमने देखा, विधि sorted
एक की उम्मीद करती है Ordering[A]
(वास्तव में, यह एक की उम्मीद करती है Ordering[B]
, जहां B >: A
)। अंदर ऐसी कोई बात नहीं है Ordering
, और कोई "स्रोत" प्रकार नहीं है जिस पर देखना है। जाहिर है, यह इसे अंदर पा रहा है A
, जो एक प्रकार का तर्क है Ordering
।
यह भी है कि विभिन्न संग्रह विधियों से CanBuildFrom
काम की अपेक्षा कैसे की जाती है : निहितार्थों को ऑब्जेक्ट ऑब्जेक्ट्स के प्रकार के मापदंडों के अंदर पाया जाता है CanBuildFrom
।
ध्यान दें : Ordering
के रूप में परिभाषित किया गया है trait Ordering[T]
, जहां T
एक प्रकार का पैरामीटर है। इससे पहले, मैंने कहा था कि स्काला ने टाइप के मापदंडों को देखा, जिसका ज्यादा मतलब नहीं है। उपरोक्त के लिए देखा गया निहितार्थ यह है कि वास्तविक प्रकार Ordering[A]
कहां A
है, प्रकार पैरामीटर नहीं: यह एक प्रकार का तर्क है Ordering
। स्कैला विनिर्देश के खंड 7.2 देखें।
यह स्काला 2.8.0 के बाद से उपलब्ध है।
नेस्टेड प्रकारों के लिए बाहरी वस्तुएँ
मैंने वास्तव में इसके उदाहरण नहीं देखे हैं। अगर कोई एक साझा कर सकता है तो मैं आभारी रहूंगा। सिद्धांत सरल है:
class A(val n: Int) {
class B(val m: Int) { require(m < n) }
}
object A {
implicit def bToString(b: A#B) = "B: %d" format b.m
}
val a = new A(5)
val b = new a.B(3)
val s: String = b // s == "B: 3"
अन्य आयाम
मुझे पूरा यकीन है कि यह एक मजाक था, लेकिन यह जवाब अप-टू-डेट नहीं हो सकता है। तो यह सवाल मत उठाइए कि क्या हो रहा है, और अगर आपने गौर किया कि यह पुराना हो गया है, तो कृपया मुझे सूचित करें ताकि मैं इसे ठीक कर सकूं।
संपादित करें
संबंधित प्रश्न: