val divide = (num: Double, den: Double) => {
num / den
}
//type of pafv1 is () => (Double,Double) => Double
val pafv1 = divide _
//type of pafv2 is Double => Double
val pafv2 = divide(_:Double,2)
为什么pafv1
的类型不是(Double,Double) => Double
?
当divide
是一种简单方法时,pafv1
的类型为(Double,Double) => Double
。
答案 0 :(得分:2)
我认为解释来自eta expansion。
Scala生成val
的getter和setter方法,这意味着divide
实际上是方法def divide = (num: Double, den: Double) => { num / den }
执行val pafv1 = divide _
时,会将其扩展为eta扩展除法版本,即() => (num: Double, den: Double) => { num / den }
为什么要进行eta扩展?因为您尝试使用方法作为值(您正在部分评估_,因此将结果强制为函数值)。
答案 1 :(得分:1)
这很奇怪...如果您编译这段代码:
class C {
val f = (n: Double, d: Double) => n / d
val pf = f _
}
带有-print
标志,已解密的代码为:
package <empty> {
class C extends Object {
private[this] val f: Function2 = _;
<stable> <accessor> def f(): Function2 = C.this.f;
private[this] val pf: Function0 = _;
<stable> <accessor> def pf(): Function0 = C.this.pf;
final <artifact> private[this] def $anonfun$f$1(n: Double, d: Double): Double = n./(d);
final <artifact> private[this] def $anonfun$pf$1(): Function2 = C.this.f();
def <init>(): C = {
C.super.<init>();
C.this.f = {
((n: Double, d: Double) => C.this.$anonfun$f$1(n, d))
};
C.this.pf = {
(() => C.this.$anonfun$pf$1())
};
()
}
}
}
一些观察:
val f
声明分为private this val f: Function2
和<stable> <accessor> def f(): Function2
。 $anonfun$pf$1()
中,该函数将所有调用重定向到C.this.f()
。pf
eta展开无参数的$anonfun$pf$1()
方法到一个不带参数并返回Function2
的函数中。如果我不得不写下一段等价的代码来演示“实际发生的事情”,那么我可能会写这样的东西:
class C2 {
var f: Function2[Double, Double, Double] = _
def fAccessor(): Function2[Double, Double, Double] = this.f
f = (n: Double, d: Double) => n / d
val pf = fAccessor _
}
在这里您看到:
fAccessor
是不带参数的方法,该方法返回Function2
pf
是访问者方法fAccessor
的eta扩展,它也接受零个参数,并返回一个Function2
。因此,可以得出结论:由于某些奇怪的原因,f _
是其他不可见的访问器方法的eta扩展。我认为这根本不应该编译,看起来像是抽象泄漏(一些依赖于综合实现的方法符号出现在任何地方)。
您可能想要的东西:
val pf: Double => Double => Double = n => f(n, _)
答案 2 :(得分:0)
我通常用case
表达式“包装”该函数:
val divide = (num: Double, den: Double) => num / den
val partialDivide: PartialFunction[(Double, Double), Double] = {
case (num: Double, den: Double) if den != 0 => divide(num, den)
}
partialDivide(4, 2)
partialDivide(4, 0) // throws a `MatchError`
您可以使用此代码on Scastie。
您可以找到关于主题here的详尽解释。
答案 3 :(得分:0)