我正在学习我大学的编程范例,并阅读讲师提供的这门课程材料,用这种方式定义了一个功能:
val double = (x: Int) => 2 * x
double: Int => Int = <function1>
但是从我自己的研究中我发现并习惯于定义相同的函数:
def d (x: Int) = 2 * x
d: (x: Int)Int
我是Scala的新手。这两个定义都给出了结果:
res21: Int = 8
将4
作为参数传递。
现在我的主要问题是为什么讲师更愿意使用val
定义一个函数?除非使用val
给出一些我不知道的附加优点,否则我认为它更长并且没有必要。此外我明白使用val
使得某个名称成为占位符,所以稍后在程序中,我可能会错误地写val double = 5
并且函数将会消失!
在这个阶段,我非常确信我学会了一种更好的定义函数的方法,除非有人告诉我。
答案 0 :(得分:13)
严格来说def d (x: Int) = 2 * x
是一个方法,而不是一个函数,但是scala可以透明地将(提升)方法转换为函数。这意味着您可以在需要d
函数的任何地方使用Int => Int
方法。
执行此转换的开销很小,因为每次都会创建一个新的Function实例。我们可以在这里看到这种情况:
val double = (x: Int) => 2 * x
def d (x: Int) = 2 * x
def printFunc(f: Int => Int) = println(f.hashCode())
printFunc(double)
printFunc(double)
printFunc(d)
printFunc(d)
导致输出如此:
1477986427
1477986427
574533740
1102091268
您可以看到使用val
显式定义函数时,我们的程序只创建一个函数,并在我们作为参数传递给printFunc
时重用它(我们看到相同的哈希码)。当我们使用def
时,每次将它传递给printFunc
时都会发生到函数的转换,并且我们使用不同的哈希码创建函数的多个实例。 Try it
尽管如此,性能开销很小并且通常不会对我们的程序产生任何实际影响,因此def
通常用于定义函数,因为许多人发现它们更简洁,更易于阅读
答案 1 :(得分:5)
在Scala中,函数值是单态的(即它们不能具有类型参数,也称为“泛型”)。如果你想要一个多态函数,你必须解决这个问题,例如通过使用方法定义它:
def headOption[A]: List[A] => Option[A] = {
case Nil => None
case x::xs => Some(x)
}
写val headOption[A]
不是有效的语法。请注意,这不是一个多态函数值,它只是一个多态方法,返回适当类型的单态函数值。
答案 2 :(得分:0)
因为您可能会遇到以下情况:
abstract class BaseClass {
val intToIntFunc: Int => Int
}
class A extends BaseClass {
override val intToIntFunc = (i: Int) => i * 2
}
因此,通过一个非常简单的例子,它的目的可能并不明显。但是,Function值本身可以传递给更高阶的函数:将函数作为参数的函数。如果查看Scala集合文档,您将看到许多将函数作为参数的方法。它是一个功能强大且功能多样的工具,但在成本/收益变得明显之前,您需要达到一定的复杂性并熟悉算法。
我还建议不要使用“double”作为标识符名称。虽然合法的Scala很容易将它与Double类型混淆。