在 Scala 中,关于函数的结果类型(result type,我们熟悉的叫法是返回值类型)在不同的情况下也是有所区别的。本来 Scala 是具有类型推断机制的,譬如我们定义 val str = “hello” 时 str 变量就会被推断为 String 类型,甚至函数返回值类型也可以由 Scala 编译器推断得出。
但是,也存在一些特殊情况需要在代码中显式地指明结果类型。在《Programming in Scala》中 41 页中说到,如果一个函数是递归的,那么必须为其显式地指明该递归函数的结果类型。其中,Scala 中的函数定义格式如下:
尝试写一个计算阶乘的递归函数来检验一下这种情况。我把代码写在名为 factorial.scala 的脚本文件中,如下:
- def factorial_01(num: Int) = {
- if(num <= 1)
- 1
- else
- factorial_01(num - 1) * num
- }
- println(factorial_01(4))
在这里,我们定义了一个名为 factorial_01的函数,看上面代码第一行与图中的函数构成,我们没有指明 factorial_01的任何函数结果类型,而仅仅只是由一个等号 = 来开始函数体的定义。在命令提示符窗口下进入到该脚本文件所在目录,使用 scala 命令执行该脚本,结果如下:
错误信息中已经能够说明了递归方法 factorial_01 需要指明结果类型。
下面是显式指明了 factorial_02函数的结果类型为 Unit(相当于 Java 中的 void 关键字,不过 Unit 在 Scala 中是一个对象,而 Java 中的 void 仅仅是一个关键字),代码如下:
- def factorial_02(num: Int, result: Int) : Unit = {
- if(num <= 1)
- result
- else
- factorial_02(num - 1, result * num)
- }
- println(factorial_02(4, 1))
我之所以修改了 factorial_02 函数的参数列表,是因为星号 * 在 Scala 中好像还有其他含义,我看过之后又忘了,有兴趣的话可以自己试一试只修改 factorial_01 的结果类型再执行一下,看一下结果如何。这里我按照上面的代码执行一下,结果如下:
呼…结果仅仅返回了一对小括号( ) ,这是 Unit 结果类型所引起的结果,类似于 null 的效果。我们再修改一下代码,把 factorial_01 中的结果类型显式地声明为 Int 类型,如下:
- def factorial_03(num: Int) :Int = {
- if(num <= 1)
- 1
- else
- factorial_03(num - 1) * num
- }
- println(factorial_03(4))
执行一下,总算是能行了,截图如下:
意外的发现,当我在脚本文件中以同样的 factorial 函数名写这几个函数时,其实就相当于 Java 中方法重载,Scala 中规定函数的重载也必须指明函数的结果类型,看看下面的代码例子:
- def factorial(num: Int) :Int = {
- if(num <= 1)
- 1
- else
- factorial(num - 1) * num
- }
- println(factorial(4))
- def factorial(num: Int, result: Int) = {
- if(num <= 1)
- result
- else
- factorial(num - 1, result * num)
- }
- println(factorial(4, 1))
很明显上面两个 factorial 函数的参数列表不相同,函数结果类型的定义也不相同:第一个的结果类型为 Int 类型,而第二个则没有任何明确的结果类型的定义。用 scala 命令执行以下,发现有以下结果:
我们看到重载(overloaded)的函数需要明确的结果类型,修改一下上面第二个函数的定义,显式指明结果类型为 Int 则可正常执行了。
题外话:
我仍然记得在《代码大全 2》中作者很明确地指出用递归来求解阶乘或者斐波那契数列的教材式讲解方法是很傻的,应该完全避免用这一类错误地运用递归来求解的讲解方法。作者在书中也给出了用 for 循环求解阶乘的例子。当时看到作者在讲解此问题时恶狠狠地用了“愚蠢”二字,所以我一直记着,+_+
本文转自 xxxx66yyyy 51CTO博客,原文链接:http://blog.51cto.com/haolloyin/384175,如需转载请自行联系原作者