9

我正在我的大学学习编程范式并阅读讲师提供的以这种方式定义函数的本课程材料:

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来定义一个函数?我认为它更长并且不是真正必要的,除非 usingval提供了一些我不知道的额外优势。此外,我了解 usingval使某些名称成为占位符,因此在程序的后期,我可能会错误地编写val double = 5并且该功能将消失!在这个阶段,我非常确信我学会了一种更好的定义函数的方法,除非有人告诉我。

4

3 回答 3

14

严格来说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

您可以看到,当使用 a 显式定义函数时val,我们的程序只创建一个函数并在我们将其作为参数传递给时重用它printFunc(我们看到相同的哈希码)。当我们使用 adef时,每次将它传递给 Function 时都会发生转换,printFunc并且我们会创建多个具有不同哈希码的 Function 实例。试试看

也就是说,性能开销很小,并且通常不会对我们的程序产生任何真正的影响,因此defs 通常用于定义函数,因为许多人发现它们更简洁且更易于阅读。

于 2013-10-26T14:09:49.940 回答
5

在 Scala 中,函数值是单态的(即它们不能有类型参数,也就是“泛型”)。如果你想要一个多态函数,你必须解决这个问题,例如通过使用一个方法定义它:

def headOption[A]: List[A] => Option[A] = {
  case Nil   => None
  case x::xs => Some(x)
}

编写 . 将不是有效的语法val headOption[A]。请注意,这并没有产生多态函数值,它只是一个多态方法,返回适当类型的单态函数值。

于 2013-10-26T14:13:39.127 回答
0

因为您可能有以下内容:

abstract class BaseClass {
  val intToIntFunc: Int => Int
}

class A extends BaseClass {
  override val intToIntFunc = (i: Int) => i * 2
}

因此,通过一个非常简单的示例,其目的可能并不明显。但是该 Function 值本身可以传递给更高阶的函数:将函数作为参数的函数。如果您查看 Scala 集合文档,您会看到许多将函数作为参数的方法。它是一个非常强大且用途广泛的工具,但在成本/收益变得明显之前,您需要达到一定的复杂性并熟悉算法。

我还建议不要使用“double”作为标识符名称。尽管 Scala 是合法的,但很容易将其与 Double 类型混淆。

于 2013-10-26T14:04:26.817 回答