2010-03-01 13 views
9

Adlandırılmış bir tanımlayıcı kullanmak yerine _ kullanmayı denediğimde neden hata alıyorum?Scala'da, `_` kullanma ve adlandırılmış tanımlayıcıyı kullanma arasındaki fark nedir?

scala> res0 
res25: List[Int] = List(1, 2, 3, 4, 5) 

scala> res0.map(_=>"item "+_.toString) 
<console>:6: error: missing parameter type for expanded function ((x$2) => "item 
".$plus(x$2.toString)) 
     res0.map(_=>"item "+_.toString) 
         ^

scala> res0.map(i=>"item "+i.toString) 
res29: List[java.lang.String] = List(item 1, item 2, item 3, item 4, item 5) 

cevap

18

Belirli adlar gibi değişken adlar yerine kullanılan alt çizgiler; Nth alt çizgi, anonim bir işlevin Nth argümanı anlamına gelir. Yani aşağıdaki eşdeğerdir:

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

List(1, 2, 3).map(_ + 1) 

Ama bunu yaparsanız: Sonra _ + 1 tarafından tanımlanan fonksiyonu onun tek argüman yok sayar ve döndüren bir işlev ile liste eşleştirdiğimize

List(1, 2, 3).map(_ => _ + 1) 

. (Derleyici ikinci çizgi vardır ne tür tahmin edemediği için bu spesifik bir örnek derlemek olmaz.) Adlandırılmış parametreleri ile eşdeğer bir örnek gibi görünecektir: Bir işlevin argümanı listesinde alt çizgi kullanarak, Kısacası

List(1, 2, 3).map(x => { y => y + 1 }) 

"Bu argümanın bedeninde bu argümanları görmezden geliyorum" anlamına gelir. Bunları vücutta kullanmak "Derleyici, lütfen benim için bir argüman listesi oluştur" anlamına gelir. İki kullanım çok iyi karışmıyor.

+1

@Scoobie Bunu güçlendirmek için, alt çizgi Scala'da birçok _different_ amacı için kullanılır. David'in açıkladığı gibi, örneğinizdeki her kullanım aslında farklı bir anlama sahiptir. Scala'da, operatör aşırı yüklenmesinden kaynaklanan sorunların oldukça iyi bir örneği olan başka anlamlar da vardır. İlk başta bununla ilgili sorunlarım varken, dürüstçe düzeltebileceğimi düşündüğümü söyleyebilirim. –

3

Bir tanıtıcıya bağlanmayacaksanız, yalnızca bu bölümü dışarıda bırakın.

res0.map("item "+_.toString) 
4

Diğer yanıtları tamamlamak için, bazı durumlarda '_' öğesini yer tutucu parametresi olarak kullanırken neden "eksik parametre türünü" aldığınızı gösteren bazı örnekler verilmiştir.

Scala'nın tür çıkarımı, içeriğine dayalı olarak bir ifadenin "beklenen" türünü dikkate alır. Bağlam yoksa, parametrelerin türünü çıkaramaz. Hata iletisinde dikkat edin, _ ilk ve ikinci örnekleri derleyici tarafından oluşturulan tanımlayıcıları x$1 ve x$2 ile değiştirilir.

scala> (_: Int) + (_: Int)   
res4: (Int, Int) => Int = <function2> 

: Her parametre yer tutucu bir tür yakıştırma ekleyebilir, Alternatif

scala> (_ + _) : ((Int, Int) => Int) 
res3: (Int, Int) => Int = <function2> 

: tüm ifade bir tür yakıştırma ekleme

scala> _ + _ 
<console>:5: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2)) 
     _ + _ 
    ^
<console>:5: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2)) 
     _ + _ 
     ^

inferencer yardımcı olmak için yeterince bağlam sağlar Sağlanan tip argümanları ile aşağıdaki işlev çağrısında, bağlam benzersizdir ve işlev türü çıkarılır.

scala> def bar[A, R](a1: A, a2: A, f: (A, A) => R) = f(a1, a2) 
bar: [A,R](a1: A,a2: A,f: (A, A) => R)R 

scala> bar[Int, Int](1, 1, _ + _) 
res5: Int = 2 

Ancak, başarısız olursa, tip parametrelerini anlaması için derleyici sorarsanız: Biz parametre listelerini currying tarafından olsa da, bunu yardımcı olabilir

scala> bar(1, 1, _ + _)   
<console>:7: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2)) 
     bar(1, 1, _ + _) 
       ^
<console>:7: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2)) 
     bar(1, 1, _ + _) 
        ^

. Burada, (1, 1) ilk parametre listesine yapılan argümanlar, A tip parametresinin Int olması gerektiği sonucunu verir. Daha sonra, f argümanı türünün (Int, Int) => ?) olması gerektiğini ve R dönüş türünün tamsayı eklemenin sonucu olan Int olduğu sonucuna varır. Standart kütüphanede Traversable.flatMap'da kullanılan aynı yaklaşımı göreceksiniz.

scala> def foo[A, R](a1: A, a2: A)(f: (A, A) => R) = f(a1, a2) 
foo: [A,R](a1: A,a2: A)(f: (A, A) => R)R 

scala> foo[Int, Int](1, 1) { _ + _ } 
res1: Int = 2 

scala> foo(1, 1) { _ + _ } 
res0: Int = 2 
İlgili konular