इसका उत्तर निम्नलिखित की परिभाषा पर मिलता है map:
def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
ध्यान दें कि इसके दो पैरामीटर हैं। पहला आपका कार्य है और दूसरा एक निहित है। यदि आप वह निहित प्रदान नहीं करते हैं, तो स्काला सबसे विशिष्ट उपलब्ध का चयन करेगी ।
के बारे में breakOut
तो, इसका उद्देश्य क्या है breakOut? प्रश्न के लिए दिए गए उदाहरण पर विचार करें, आप स्ट्रिंग की एक सूची लेते हैं, प्रत्येक स्ट्रिंग को टुपल में बदलते हैं (Int, String), और फिर Mapउसमें से एक का उत्पादन करते हैं। सबसे स्पष्ट तरीका यह है कि एक मध्यस्थ List[(Int, String)]संग्रह का उत्पादन होगा , और फिर इसे परिवर्तित करें।
यह देखते हुए कि परिणामी संग्रह का उत्पादन करने के लिए mapएक Builderका उपयोग करता है , क्या यह मध्यस्थ को छोड़ना Listऔर परिणामों को सीधे एक में इकट्ठा करना संभव नहीं होगा Map? जाहिर है, हाँ, यह है। हालांकि, ऐसा करने के लिए, हमें एक उचित पास करने की आवश्यकता होती CanBuildFromहै map, और ठीक वैसा ही breakOutहोता है।
आइए, फिर देखें breakOut: की परिभाषा पर :
def breakOut[From, T, To](implicit b : CanBuildFrom[Nothing, T, To]) =
new CanBuildFrom[From, T, To] {
def apply(from: From) = b.apply() ; def apply() = b.apply()
}
ध्यान दें कि breakOutपैरामीटर किया गया है, और यह कि इसका एक उदाहरण देता है CanBuildFrom। जैसा कि होता है, प्रकार From, Tऔर Toपहले से ही अनुमान लगाया गया है, क्योंकि हम जानते हैं कि mapउम्मीद है CanBuildFrom[List[String], (Int, String), Map[Int, String]]। इसलिए:
From = List[String]
T = (Int, String)
To = Map[Int, String]
यह निष्कर्ष निकालने के लिए कि breakOutस्वयं द्वारा प्राप्त निहितार्थ की जांच करें । यह प्रकार का होता है CanBuildFrom[Nothing,T,To]। हम पहले से ही इन सभी प्रकारों को जानते हैं, इसलिए हम यह निर्धारित कर सकते हैं कि हमें प्रकार के निहितार्थ की आवश्यकता है CanBuildFrom[Nothing,(Int,String),Map[Int,String]]। लेकिन क्या ऐसी कोई परिभाषा है?
आइए नजर डालते हैं CanBuildFromपरिभाषा:
trait CanBuildFrom[-From, -Elem, +To]
extends AnyRef
तो CanBuildFromइसके पहले प्रकार के पैरामीटर पर गर्भ-संस्करण है। क्योंकि Nothingएक निचला वर्ग है (यानी, यह सब कुछ का एक उपवर्ग है), जिसका अर्थ है कि किसी भी वर्ग का उपयोग किया जा सकता है Nothing।
चूंकि इस तरह के एक बिल्डर मौजूद है, स्काला इसका उपयोग वांछित उत्पादन करने के लिए कर सकती है।
बिल्डर्स के बारे में
स्काला के संग्रह पुस्तकालय के बहुत सारे तरीकों में मूल संग्रह लेना, इसे किसी तरह संसाधित करना ( mapप्रत्येक तत्व को बदलना), और परिणाम को एक नए संग्रह में संग्रहीत करना शामिल है।
कोड पुन: उपयोग को अधिकतम करने के लिए, परिणामों का यह भंडारण एक बिल्डर ( scala.collection.mutable.Builder) के माध्यम से किया जाता है , जो मूल रूप से दो कार्यों का समर्थन करता है: तत्वों को जोड़ना, और परिणामी संग्रह को वापस करना। इस परिणामी संग्रह का प्रकार बिल्डर के प्रकार पर निर्भर करेगा। इस प्रकार, एक Listबिल्डर वापस आ जाएगा List, एक Mapबिल्डर वापस आ जाएगा Map, और इसी तरह। mapविधि के कार्यान्वयन के परिणाम के प्रकार के साथ खुद को चिंता करने की आवश्यकता नहीं है: बिल्डर इसका ख्याल रखता है।
दूसरी ओर, इसका मतलब है कि mapकिसी भी तरह इस बिल्डर को प्राप्त करने की आवश्यकता है। स्केल 2.8 कलेक्शंस को डिजाइन करते समय समस्या का सामना करना पड़ा कि कैसे सबसे अच्छा संभव बिल्डर चुनना था। उदाहरण के लिए, अगर मैं लिखना Map('a' -> 1).map(_.swap)चाहता था , तो मैं Map(1 -> 'a')वापस जाना चाहता हूं । दूसरी ओर, यह ( Map('a' -> 1).map(_._1)ए ) वापस नहीं लौट सकता है ।MapIterable
Builderज्ञात प्रकार के अभिव्यक्ति से सर्वोत्तम संभव उत्पादन का जादू इस CanBuildFromनिहितार्थ के माध्यम से किया जाता है ।
के बारे में CanBuildFrom
यह समझने के लिए कि क्या चल रहा है, मैं एक उदाहरण दूंगा जहां संग्रहित किया जा रहा है, Mapबजाय एक है List। मैं Listबाद में वापस जाऊंगा । अभी के लिए, इन दो भावों पर विचार करें:
Map(1 -> "one", 2 -> "two") map Function.tupled(_ -> _.length)
Map(1 -> "one", 2 -> "two") map (_._2)
पहला रिटर्न ए Mapऔर दूसरा रिटर्न ए Iterable। फिटिंग कलेक्शन लौटाने का जादू है CanBuildFrom। आइए mapइसे समझने के लिए फिर से परिभाषा पर विचार करें ।
विधि mapसे विरासत में मिली है TraversableLike। यह चालू है Bऔर That, और प्रकार के मापदंडों का उपयोग करता है Aऔर Repr, जो वर्ग को मानकीकृत करता है। आइए दोनों परिभाषाओं को एक साथ देखें:
वर्ग TraversableLikeके रूप में परिभाषित किया गया है:
trait TraversableLike[+A, +Repr]
extends HasNewBuilder[A, Repr] with AnyRef
def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
यह समझने के लिए कि कहां Aऔर कहां Reprसे आया है, आइए Mapस्वयं की परिभाषा पर विचार करें :
trait Map[A, +B]
extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
क्योंकि TraversableLikeउन सभी लक्षणों को विरासत में मिला है जो विस्तार करते हैं Map, Aऔर Reprउनमें से किसी से विरासत में प्राप्त किया जा सकता है। पिछले एक को वरीयता मिलती है, हालांकि। इसलिए, अपरिवर्तनीय Mapऔर इसे जोड़ने वाले सभी लक्षणों की परिभाषा के बाद TraversableLike, हमारे पास है:
trait Map[A, +B]
extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]]
extends MapLike[A, B, This]
trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]]
extends PartialFunction[A, B] with IterableLike[(A, B), This] with Subtractable[A, This]
trait IterableLike[+A, +Repr]
extends Equals with TraversableLike[A, Repr]
trait TraversableLike[+A, +Repr]
extends HasNewBuilder[A, Repr] with AnyRef
यदि आप Map[Int, String]श्रृंखला के सभी प्रकारों के प्रकार के मापदंडों को पास करते हैं , तो हम पाते हैं कि प्रकार पास किए गए हैं TraversableLike, और इस प्रकार, द्वारा उपयोग किया जाता है map:
A = (Int,String)
Repr = Map[Int, String]
उदाहरण पर वापस जाने पर, पहला मानचित्र प्रकार का एक फ़ंक्शन प्राप्त कर रहा है ((Int, String)) => (Int, Int)और दूसरा मानचित्र प्रकार का फ़ंक्शन प्राप्त कर रहा है ((Int, String)) => String। मैं डबल कोष्ठक का उपयोग करने पर जोर देता हूं यह एक टपल प्राप्त किया जा रहा है, जैसा कि Aहमने देखा था उसी प्रकार का है ।
उस जानकारी के साथ, आइए अन्य प्रकारों पर विचार करें।
map Function.tupled(_ -> _.length):
B = (Int, Int)
map (_._2):
B = String
हम देख सकते हैं कि प्रकार पहले mapसे लौटा है Map[Int,Int], और दूसरा है Iterable[String]। को देखते हुए mapकी परिभाषा यह है कि इन के मूल्यों को देखने के लिए आसान है That। लेकिन वे कहां से आते हैं?
यदि हम शामिल कक्षाओं की साथी वस्तुओं के अंदर देखते हैं, तो हम उन्हें प्रदान करने वाले कुछ निहित घोषणाओं को देखते हैं। वस्तु पर Map:
implicit def canBuildFrom [A, B] : CanBuildFrom[Map, (A, B), Map[A, B]]
और वस्तु पर Iterable, जिसका वर्ग इसके द्वारा बढ़ाया गया है Map:
implicit def canBuildFrom [A] : CanBuildFrom[Iterable, A, Iterable[A]]
ये परिभाषाएँ मानकीकृत के लिए कारखानों को प्रदान करती हैं CanBuildFrom।
Scala उपलब्ध सबसे विशिष्ट निहित का चयन करेगा। पहले मामले में, यह पहला था CanBuildFrom। दूसरे मामले में, जैसा कि पहले मैच नहीं हुआ, उसने दूसरे को चुना CanBuildFrom।
वापस प्रश्न पर
चलो प्रश्न के लिए कोड को देखते हैं, List'और एस mapएस डेफिनिशन (फिर) को देखने के लिए कैसे प्रकार पर आधारित हैं:
val map : Map[Int,String] = List("London", "Paris").map(x => (x.length, x))(breakOut)
sealed abstract class List[+A]
extends LinearSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqLike[A, List[A]]
trait LinearSeqLike[+A, +Repr <: LinearSeqLike[A, Repr]]
extends SeqLike[A, Repr]
trait SeqLike[+A, +Repr]
extends IterableLike[A, Repr]
trait IterableLike[+A, +Repr]
extends Equals with TraversableLike[A, Repr]
trait TraversableLike[+A, +Repr]
extends HasNewBuilder[A, Repr] with AnyRef
def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
का प्रकार List("London", "Paris")है List[String], इसलिए प्रकार Aऔर Reprपरिभाषित TraversableLikeहैं:
A = String
Repr = List[String]
के लिए प्रकार (x => (x.length, x))है (String) => (Int, String), इसलिए प्रकार Bहै:
B = (Int, String)
अंतिम अज्ञात प्रकार, Thatके परिणाम का प्रकार है map, और हमारे पास पहले से ही है:
val map : Map[Int,String] =
इसलिए,
That = Map[Int, String]
इसका मतलब है breakOut, आवश्यक रूप से, का एक प्रकार या उपप्रकार वापस करना चाहिए CanBuildFrom[List[String], (Int, String), Map[Int, String]]।
List, लेकिन करने के लिए हैmap।