下划线_
不适用于以下代码中的某些情况:
case class Item
(
para: Int
)
val a = List(1, 2)
val b = List(Item(1), Item(2))
a foreach {
perA => println(perA * 2) // Line A: ok
}
a foreach {
println(_) // Line B: ok
}
a foreach {
println(_ * 2) // Line C: not ok
}
b foreach {
perB => println(perB.para) // line D: ok
}
b foreach {
println(_.para) // line E: not ok
}
有人可以向我解释关于C&线的问题吗? E行,谢谢。
答案 0 :(得分:3)
TL; DR: lambda的参数可以插入到意外的位置。而不是采取
a foreach { println(_.blah) }
并建立
a foreach { x => println(x.blah) }
,编译器改为构建
a foreach { println( x => x.blah ) }
然后无法派生参数x
的类型。
A)这是写下lambda的最明确的方法,唯一能让它更清晰的方法就是添加一个类型:
a foreach { perA => println(perA * 2) }
与
相同a foreach { (x: Int) => println(x * 2) }
这显然有效。
B)这是有效的,因为它是记录从println
自动生成的函数的一种方法。它相当于以下六种变体中的任何一种:
a foreach { (x: Int) => println(x) }
a foreach { x => println(x) }
a foreach { println(_) }
a foreach { println _ }
a foreach { println }
a foreach println
C)由于* 2
,此处为
a foreach { println(_ * 2) }
不再仅仅被视为println(_)
。相反,它被解释为
a foreach { println( { (x: ??!) => x * 2 } ) }
并且由于println
不接受函数值参数,因此它无法确定x
的类型应该是什么,并以错误退出。
D)基本上与 A 相同,它有效,我希望它清楚。
E) C 的变体,但这一次,类型检查器不是在寻找方法*(i: Int)
的东西,但是相反,它正在寻找成员para
。
这里:
b foreach { println(_.para) }
再次被解释为foreach
,其函数忽略b
的元素并返回表达式println(_.para)
的常量值,
那就是:
b foreach { println( { (x: ??!) => x.para } ) }
同样,内部表达式println( { (x: ??!) => x.para } )
没有任何意义,因为println
不期望函数值的参数(它可以处理Any
,但它还不够派生x
)的类型。