2011-01-18 12 views
64

Neden bu yapı Scala'da bir Tür Uyuşmazlığı hatasına neden oluyor? Ben List ile Bazı geçersenizAnlamak İçin Scala'da Uyuşmazlık Türleri

for (first <- Some(1); second <- List(1,2,3)) yield (first,second) 

<console>:6: error: type mismatch; 
found : List[(Int, Int)] 
required: Option[?] 
     for (first <- Some(1); second <- List(1,2,3)) yield (first,second) 

ince derler:

for (first <- List(1,2,3); second <- Some(1)) yield (first,second) 
res41: List[(Int, Int)] = List((1,1), (2,1), (3,1)) 

Bu aynı zamanda çalışıyor: comprehensions için

for (first <- Some(1); second <- Some(2)) yield (first,second) 
+2

Scala'nın başarısız örnekte geri dönmesini ne bekliyorsunuz? –

+0

Yazarken, bir Option [Liste [(Int, Int)]] alacağımı düşündüm. –

cevap

99

map veya flatMap yöntemine çağrıları dönüştürülür . Örneğin bu için:

List(1).flatMap(x => List(1,2,3).map(y => (x,y))) 

Bu nedenle, (bu durumda, List(1) olarak) birinci döngü değeri flatMap yöntem çağrısı alır:

for(x <- List(1) ; y <- List(1,2,3)) yield (x,y) 

bu olur. Bir List üzerinde flatMap başka List döndürür yana, anlama için sonucu elbette bir List olacaktır. (Bu benim için yeni: comprehensions hep Seq s bile mutlaka akışları neden uygun değil.)

Şimdi

, flatMapOption beyan nasıl bir göz atın:

def flatMap [B] (f: (A) ⇒ Option[B]) : Option[B] 

Keep bu akılda. haritanın bir dizisine dönüştürülür alır nasıl anlama (Some(1) ile bir) için hatalı görelim çağırır: Artık

Some(1).flatMap(x => List(1,2,3).map(y => (x, y))) 

, bu flatMap çağrısının parametresi bir List döndüren şey olduğunu görmek kolaydır, ancak gerektiği gibi bir Option değil.

şeyi düzeltmek için, aşağıdakileri yapabilirsiniz: gayet derler

for(x <- Some(1).toSeq ; y <- List(1,2,3)) yield (x, y) 

. Sıklıkla varsayıldığı gibi, Option'un Seq'un bir alt türü olmadığını belirtmek gerekir.

4

Muhtemelen yinelenen olma seçeneğiyle Opsiyon ile ilgili bir şey vardır. Kapalı Option.option2Iterable, derleyicinin yinelenen olması için ikinci olarak beklediği durumu ele alacaktır. Derleyici sihrinin, döngü değişkeninin türüne bağlı olarak farklı olmasını beklerim.

24

Hatırlamak için kolay bir ipucu, , bu durumda ilk üretecin, Option [Int] koleksiyonunun türünü döndürmeye çalışır. Yani, Bazı (1) ile başlarsanız, Seçenek [T] sonucunu beklemeniz gerekir.

List türünde bir sonuç istiyorsanız, bir Liste oluşturucusuyla başlamanız gerekir.

Neden bu kısıtlama var ve her zaman bir çeşit sıralamak isteyeceğinizi varsaymıyorsunuz? Option dönmek için mantıklı bir durum olabilir.Belki de bir Option[List[Int]] almak için bir şey ile birleştirmek istediğiniz bir Option[Int] var, aşağıdaki işlevle: (i:Int) => if (i > 0) List.range(0, i) else None; Eğer o zaman bu yazıp şeyler "mantıklı" olmadığı zamanlarda Hiçbiri alabilir:

comprehensions için genel durumda genişletilmiş nasıl
val f = (i:Int) => if (i > 0) Some(List.range(0, i)) else None 
for (i <- Some(5); j <- f(i)) yield j 
// returns: Option[List[Int]] = Some(List(0, 1, 2, 3, 4)) 
for (i <- None; j <- f(i)) yield j 
// returns: Option[List[Int]] = None 
for (i <- Some(-3); j <- f(i)) yield j 
// returns: Option[List[Int]] = None 

aslında tip M[T] bir nesne birleştirmek için oldukça genel bir mekanizmadır M[U] türünde bir nesne almak için (T) => M[U] işlevine sahip. Örneğinizde M, Seçenek veya Liste olabilir. Genel olarak aynı tip M olmalıdır. Dolayısıyla, Option'u Listeyle birleştiremezsiniz. M olabilir diğer şeylerin örnekleri için, subclasses of this trait bakın.

List[T]'un (T) => Option[T] ile birleştirilmesi, neden Listeye başladığınız halde çalışıyor mu? Bu durumda kütüphane, mantıklı olduğu daha genel bir tip kullanır. Böylece, Listeyi Traversable ile birleştirebilir ve Option'dan Traversable'a dolaylı bir dönüşüm gerçekleşir.

En alt satır şudur: ifadenin hangi türün döndürüleceğini ve bu türle ilk jeneratör olarak başlamayı düşünün. Gerekirse, o türe sarın.