Function 用于在Scala中定义函数的def或val

Function 用于在Scala中定义函数的def或val,function,scala,functional-programming,Function,Scala,Functional Programming,我正在我的大学学习编程范例,并阅读讲师提供的课程材料,讲师以这种方式定义函数: val double = (x: Int) => 2 * x double: Int => Int = <function1> 我是斯卡拉的新手。两种定义都给出了以下结果: res21: Int = 8 将4作为参数传递时。 现在我的主要问题是,为什么讲师更喜欢使用val来定义函数?我认为它很长,并且不是真正必要的,除非使用val提供了一些我不知道的额外优势。此外,我知道使用val会使一些

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

val double = (x: Int) => 2 * x
double: Int => Int = <function1>
我是斯卡拉的新手。两种定义都给出了以下结果:

res21: Int = 8
4
作为参数传递时。
现在我的主要问题是,为什么讲师更喜欢使用
val
来定义函数?我认为它很长,并且不是真正必要的,除非使用
val
提供了一些我不知道的额外优势。此外,我知道使用
val
会使一些名称成为占位符,因此在程序的后面,我可能会错误地写入
val double=5
,函数将消失!
在这个阶段,我确信我学会了一种更好的定义函数的方法,除非有人告诉我另外一种方法。

因为你可能会有如下情况:

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

class A extends BaseClass {
  override val intToIntFunc = (i: Int) => i * 2
}
因此,通过一个非常简单的例子,它的目的可能并不明显。但函数值本身可以传递给高阶函数:以函数为参数的函数。如果查看Scala collections文档,您将看到许多将函数作为参数的方法。这是一个功能强大且用途广泛的工具,但在成本/效益变得明显之前,您需要达到一定的复杂性并熟悉算法


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

严格来说
def d(x:Int)=2*x
是一种方法,而不是函数,但是Scala可以透明地将(lift)方法转换为函数。这意味着您可以在任何需要
Int=>Int
函数的地方使用
d
方法

由于每次都会创建一个新的函数实例,因此执行此转换的开销很小。我们可以在这里看到这种情况:

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
时,都会发生函数转换,我们使用不同的哈希代码创建函数的多个实例


这就是说,性能开销很小,通常不会对我们的程序产生任何实际影响,因此通常使用
def
s来定义函数,因为许多人发现它们更简洁、更易于阅读。

在Scala中,函数值是单态的(即它们不能有类型参数,也就是“泛型”)。如果需要多态函数,则必须解决此问题,例如,使用以下方法定义它:

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

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

我没有资格对Scala说一些确定的话,但在函数定义为
double
之后,您是否尝试过实际执行
val double=5
?我的印象是,一旦定义了一个名字,就不可能重新定义它。在任何情况下,
val
def
在这里产生相同的结果。这仅仅是风格上的差异。通常,使用
def
定义函数更为清晰,但有时使用
val
定义函数更为合理。如果您不确定,我建议您使用
def
,因为它不太可能引起任何混淆。是的,我使用了
val double=5
,键入了
double
,并且获得了
res24:Int=5
可能的副本。大多数情况下,两种变体都可以使用,因此这是一个文体问题。我同意你更喜欢方法,但这只是一种偏好。“
val
使一些名称成为占位符”-这没关系,
def d
还引入了一个符号
d
,你可以通过重新定义它来隐藏它。在这方面,两者之间没有真正的区别。最近运行了一个基准测试,显示“eta扩展”(将方法作为参数传递时将其提升到函数)并不会导致性能损失。好帖。我想垃圾收集也可能会增加,但我想这也会很小/不存在。a指的是什么?有一段时间我看到了def name[T](),我不明白它在scala中是什么意思
def headOption[A]: List[A] => Option[A] = {
  case Nil   => None
  case x::xs => Some(x)
}