2013-10-26 91 views
8

我正在学习编程范式在我的大学定义功能和阅读由定义的函数这样的讲师提供此课程材料:高清或Val在斯卡拉

val double = (x: Int) => 2 * x 
double: Int => Int = <function1> 

但是从我自己的研究,我发现并习惯于像这样定义相同的功能:

def d (x: Int) = 2 * x 
d: (x: Int)Int 

我是新来的斯卡拉。而且两者的定义给出的结果是:

res21: Int = 8 

一旦通过4作为参数。 现在我的主要问题是为什么讲师倾向于使用val来定义一个函数?除非使用val给出了一些我不知道的附加优点,否则我认为它的时间更长且没有必要。除此之外,我知道使用val会在程序的后面写出一些名称作为占位符,所以我可能会错误地编写val double = 5,并且该函数将消失! 在这个阶段,我确信我学会了定义一个函数的更好方式,除非别人会告诉我。

+0

我没有资格说一些明确的关于斯卡拉,但你想真正做'VAL双= 5'的功能被定义为后'double'?我有这样的印象,一旦它被定义,就不可能重新定义一个名字。无论如何,'val'和'def'在这里都会产生相同的结果。区别仅仅在于风格。通常,用'def'定义一个函数更为明显,但有时用'val'定义它是有意义的。如果你不确定,我会建议你使用'def',因为它不太可能引起任何混淆。 – kqr

+0

是的,我做了'VAL双= 5',键入'double'并得到了'res24:Scala的方法和功能的差异]的诠释= 5' – Emanuel

+0

可能重复(http://stackoverflow.com/questions/2529184 /差之间-方法和 - 功能合阶) –

回答

12

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

执行此转换的开销很小,因为每次都会创建一个新的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 s的通常用于定义功能尽可能多的人发现他们更简洁,更易于阅读。

+2

[某些人(http://japgolly.blogspot.com.au/2013/10/scala-methods-vs-functions.html)跑的基准就在最近,显示出“ETA-扩张”(解除方法一个函数作为参数传递时)并不真的会导致性能损失。 –

+0

好帖子。我想也有可能是垃圾收集的增加,但我想,这将是一个微小的/不存在了。 – theon

0

因为你可能有类似以下内容:

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

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

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

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

5

在斯卡拉,函数值是单形的(即它们不能有类型参数,又称“泛型”)。如果你想要一个多态函数,你必须使用方法定义它来解决这个问题,例如:

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

它不会是有效的语法来写val headOption[A]。请注意,这并没有使一个多态函数值,它仅仅是一个多态的方法,返回相应类型的单态函数值。

+0

+1这是一个重要的区别要意识到的 – theon