Cevap şu tanımda bulunur map
:
def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
İki parametresi olduğunu unutmayın. Birincisi sizin işleviniz, ikincisi örtüktür. Bunu örtük olarak sağlamazsanız, Scala mevcut olan en spesifik olanı seçecektir .
hakkında breakOut
Peki, amacı breakOut
nedir? Soru için verilen örneği düşünün, bir dize listesi alın, her dize bir tuple dönüştürün (Int, String)
ve sonra bir Map
dışarı üretmek . Bunu yapmanın en belirgin yolu, bir ara List[(Int, String)]
koleksiyon oluşturur ve sonra onu dönüştürür.
Ortaya çıkan koleksiyonu üretmek için a'nın map
kullanıldığı göz önüne alındığında, aracıyı Builder
atlamak List
ve sonuçları doğrudan a'ya toplamak mümkün olmaz Map
mı? Açıkçası, evet, öyle. Bununla birlikte, bunu yapmak için uygun olanı geçmemiz CanBuildFrom
gerekiyor map
ve tam olarak breakOut
bunu yapıyor.
Öyleyse, tanımına bakalım 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()
}
Not o breakOut
parametreli ve bir örneğini döndürür yani CanBuildFrom
. O sırada da, türleri From
, T
ve To
bunu biliyoruz çünkü zaten anlaşılmaktadır edilmiştir map
bekliyor CanBuildFrom[List[String], (Int, String), Map[Int, String]]
. Bu nedenle:
From = List[String]
T = (Int, String)
To = Map[Int, String]
Sonuç olarak, breakOut
kendisi tarafından alınan örtük olanı inceleyelim . Türlüdür CanBuildFrom[Nothing,T,To]
. Tüm bu türleri zaten biliyoruz, böylece bir örtük türe ihtiyacımız olduğunu belirleyebiliriz CanBuildFrom[Nothing,(Int,String),Map[Int,String]]
. Fakat böyle bir tanım var mı?
Hadi CanBuildFrom
tanımına bakalım :
trait CanBuildFrom[-From, -Elem, +To]
extends AnyRef
Yani CanBuildFrom
ilk tip parametre üzerinde kontra-türüdür. Çünkü Nothing
bir alt sınıf (yani her şeyin bir alt sınıfıdır), yani herhangi bir sınıfın yerine kullanılabileceği anlamına gelir Nothing
.
Böyle bir inşaatçı mevcut olduğundan, Scala bunu istenen çıktıyı üretmek için kullanabilir.
İnşaatçılar Hakkında
Scala'nın koleksiyon kütüphanesinden birçok yöntem orijinal koleksiyonu almak, bir şekilde işlemek ( map
her bir öğeyi dönüştürmek için) ve sonuçları yeni bir koleksiyonda saklamaktan ibarettir .
Kodun yeniden kullanımını en üst düzeye çıkarmak için, sonuçların bu şekilde saklanması temel olarak iki işlemi destekleyen bir oluşturucu ( scala.collection.mutable.Builder
) aracılığıyla yapılır : öğeleri ekleme ve sonuçta elde edilen koleksiyonu döndürme. Elde edilen bu koleksiyonun türü, üreticinin türüne bağlı olacaktır. Böylece, bir List
inşaatçı a geri döner List
, bir Map
inşaatçı a geri döner Map
, vb. map
Yöntemin uygulanması , sonucun türüyle ilgilenmek zorunda değildir: oluşturucu bununla ilgilenir.
Öte yandan, bunun bir map
şekilde bu kurucuyu alması gerektiği anlamına gelir . Scala 2.8 Koleksiyonlarını tasarlarken karşılaşılan sorun, mümkün olan en iyi kurucunun nasıl seçileceği idi. Örneğin, eğer yazacak Map('a' -> 1).map(_.swap)
olsaydım, Map(1 -> 'a')
geri dönmek isterdim . Öte yandan, a Map('a' -> 1).map(_._1)
döndüremez Map
( a döndürür Iterable
).
Builder
Bilinen ifade türlerinden mümkün olan en iyisini üretme büyüsü, bu CanBuildFrom
örtük yoluyla gerçekleştirilir .
hakkında CanBuildFrom
Neler olduğunu daha iyi açıklamak için, haritalanan koleksiyonun a Map
yerine bir örnek vereceğim List
. Daha List
sonra geri döneceğim . Şimdilik, şu iki ifadeyi düşünün:
Map(1 -> "one", 2 -> "two") map Function.tupled(_ -> _.length)
Map(1 -> "one", 2 -> "two") map (_._2)
Birincisi a Map
, ikincisi bir Iterable
. Uygun bir koleksiyon döndürmenin büyüsü işidir CanBuildFrom
. map
Anlamak için tekrar tanımını düşünelim .
Yöntem map
miras alınır TraversableLike
. Bu üzerinde parametre belirlenmiştir B
ve That
ve markaları tip parametrelerin kullanmak A
ve Repr
sınıfını parametreleştirdiğinizde. Her iki tanımı birlikte görelim:
Sınıf TraversableLike
şu şekilde tanımlanır:
trait TraversableLike[+A, +Repr]
extends HasNewBuilder[A, Repr] with AnyRef
def map[B, That](f : (A) => B)(implicit bf : CanBuildFrom[Repr, B, That]) : That
Nereden A
ve Repr
nereden geldiğini anlamak için, Map
kendisinin tanımını düşünelim :
trait Map[A, +B]
extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
Çünkü TraversableLike
uzatmak tüm özellikleri ile devralınan Map
, A
ve Repr
bunlardan herhangi miras edilebilir. Sonuncusu tercih edilir. Yani, değişmez tanımını Map
ve onu bağlayan tüm özellikleri takip ederek TraversableLike
, elimizde:
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
Eğer tip parametrelerini Map[Int, String]
zincirin altından geçirirseniz, geçilen tiplerin TraversableLike
ve dolayısıyla kullanılan tiplerin map
:
A = (Int,String)
Repr = Map[Int, String]
Örneğe dönersek, ilk harita bir tür işlev alıyor ((Int, String)) => (Int, Int)
ve ikinci harita bir tür işlev alıyor ((Int, String)) => String
. Gördüğümüz gibi, alınan bir demet olduğunu vurgulamak için çift parantez kullanıyorum A
.
Bu bilgi ile diğer türleri ele alalım.
map Function.tupled(_ -> _.length):
B = (Int, Int)
map (_._2):
B = String
Biz ilk tarafından döndürülen tip olduğunu görebilirsiniz map
olduğunu Map[Int,Int]
ve ikinci Iterable[String]
. map
Tanımına bakıldığında, bunların değerleri olduğunu görmek kolaydır That
. Ama nereden geliyorlar?
İlgili sınıfların yardımcı nesnelerinin içine bakarsak, bunları sağlayan bazı örtülü bildirimler görürüz. Nesnede Map
:
implicit def canBuildFrom [A, B] : CanBuildFrom[Map, (A, B), Map[A, B]]
Iterable
Sınıfı genişletilen nesnede Map
:
implicit def canBuildFrom [A] : CanBuildFrom[Iterable, A, Iterable[A]]
Bu tanımlar parametreli fabrikalar sağlar CanBuildFrom
.
Scala, mevcut olan en kesin örtülü yöntemi seçecektir. İlk durumda, ilk oldu CanBuildFrom
. İkinci durumda, birincisi eşleşmediği için ikincisini seçti CanBuildFrom
.
Soruya Geri Dön
Türlerin nasıl çıkarıldığını görmek için List
's ve map
' tanımının (tekrar) sorusunun kodunu görelim :
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
Türü List("London", "Paris")
olan List[String]
türleri, böylece A
ve Repr
tanımlanan TraversableLike
gibidir:
A = String
Repr = List[String]
Tip (x => (x.length, x))
olduğu (String) => (Int, String)
türü, yani B
geçerli:
B = (Int, String)
Son bilinmeyen tür, That
sonucun türüdür map
ve zaten buna sahibiz:
val map : Map[Int,String] =
Yani,
That = Map[Int, String]
Bu breakOut
, mutlaka, türünü veya alt türünü döndürmelidir CanBuildFrom[List[String], (Int, String), Map[Int, String]]
.
List
, bunlarlamap
.