इसका उत्तर निम्नलिखित की परिभाषा पर मिलता है 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)
ए ) वापस नहीं लौट सकता है ।Map
Iterable
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
।