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)
}