我正在关注本教程,我看到了这段代码:
def totalCostWithDiscountFunctionParameter(donutType: String)(quantity: Int)(f: Double => Double): Double = {
println(s"Calculating total cost for $quantity $donutType")
val totalCost = 2.50 * quantity
println("inside totalCostWithDiscountFunctionParameter")
f(totalCost)
}
def applyDiscount(totalCost: Double): Double = {
val discount = 2 // assume you fetch discount from database
totalCost - discount
}
println(s"Total cost of 5 Glazed Donuts with discount function = ${totalCostWithDiscountFunctionParameter("Glazed Donut")(5)(applyDiscount(_))}")
_
中的applyDiscount(_)
有什么意义?我也可以删除它,只需按名称applyDiscount
传递函数,代码就可以了。下划线有什么意义?它是一回事吗?
答案 0 :(得分:1)
applyDiscount(_)
是placeholder syntax for anonymous functions。这扩展到:
x => applyDiscount(x)
将applyDiscount
方法传递给函数时,即:
totalCostWithDiscountFunctionParameter("5")(applyDiscount)
然后scalac将执行eta-expansion,这意味着将方法转换为函数值。
这些是否具有完全相同的语义?关闭,但不完全。请考虑What are all the uses of an underscore in Scala?中给出的以下示例(稍微修改,完全归功于@Owen的示例和提供的答案)
trait PlaceholderExample {
def process[A](f: A => Unit)
val set: Set[_ => Unit]
set.foreach(process) // Error
set.foreach(process(_)) // No Error
}
第二次成功时编译时的第一个错误,为什么会这样?让我们看看用-Xprint:typer
编译的代码:
λ scalac -Xprint:typer Test.scala
FooBar.scala:11: error: polymorphic expression cannot be instantiated to expected type;
found : [A](A => Unit) => Unit
required: (Function1[_, Unit]) => ?
set.foreach(process) // Error
^
[[syntax trees at end of typer]]
package yuval.tests {
abstract trait PlaceholderExample extends scala.AnyRef {
def /*PlaceholderExample*/$init$(): Unit = {
()
};
def process[A](f: A => Unit): Unit;
<stable> <accessor> val set: Set[Function1[_, Unit]];
PlaceholderExample.this.set.foreach[U](process);
PlaceholderExample.this.set.foreach[Unit](((x$1: Function1[_, Unit]) => PlaceholderExample.this.process[_$1](x$1)))
}
}
您首先看到的是编译错误,因为scalac无法将方法process
从多态方法扩展为单态函数。这意味着,当scalac尝试将A
绑定到实际类型时,它会查找类型(_ => Unit) => ?
,但会失败,因为_
(存在性)不是类型。
另一方面,扩展为x => process(x)
的第二个示例进行编译,因为当scalac遇到没有显式类型注释的lambda表达式时,它会查看方法签名的类型(在我们的例子中,{{ 1}}期望foreach
,它被归类为类型)并成功地将类型参数绑定到_ => Unit
。
因此,在大多数情况下,你会发现这两个是同构的(尽管它们确实不是)(甚至IntelliJ建议我可以写一个而不是另一个),但是有一些边缘情况可以区分一个另一个。