本人将结合《Scala学习手册》一书的内容,以Java程序员的视角为第一视角,用几篇小文来快速入门Scala。本篇内容为Scala函数。
函数编写形式
在Scala中编写函数和在Java中编写方法,形式上还是存在一些差别的。
普遍式
这种我称之为普遍式:
|
|
和Java不同,Scala类型的写法后置了。比如小括号内的: <type>
表示行参的类型,中括号内的可选内容: <type>
表示expression的返回类型;
这里的=
类似Java 8里Lambda表达式的->
;
实例:
|
|
大括号式
这种方式我称之为大括号式,因为采用{}
:
|
|
实例:
|
|
讨论[: <type>] =
存在与否的情况;
不存在[: <type>] = 的情况:
大括号内只可出现初始化声明,表达式以及语句;
这实际上是一个procedure,没有返回值的函数,通常并不推荐,因为它会“沉默”带返回值的表达式,例如:
|
|
可见虽然a + 1是一个有返回的表达式,但是返回值被忽略了;
存在[: <type>] = 的情况:
当添加了=
后,就不是一个procedure了,大括号也可以单纯是{a}
这种形式了,稍加更改前文中的实例再次运行:
|
|
调用函数后有输出结果:Int = 3;
无参式
这里指的是定义无参数输入的函数形式也存在两种,分别是无括号和有括号;
无括号:
|
|
注意c1:
后直接是String,调用函数直接在REPL输入c1,此时不能输入c1();
有括号:
|
|
此次c2:
后接的是()String,通过输入c2而非c2()来调用该函数也是可以的;
关于使用括号的约定:若函数有副作用,定义时应该加空括号,比如函数向控制台写数据等;
递归函数
本站文章《学习Java函数式编程(五):函数式思维与尾递归》已经提到了Java不支持尾递归优化,而Scala等JVM平台下的语言是通过将递归转化为循环来实现伪递归优化的。维基百科和相关文章都提到了,此方法不能优化交叉调用的尾递归,这里不深入说开去,毕竟本篇核心是入门Scala,但是并不难理解,文章末尾给出一些参考链接。
Scala提供了伪递归注解:
|
|
该注解用来帮助程序员进行伪递归优化;
嵌套函数
Scala函数按照函数名以及其参数类型列表来区分彼此;
Scala支持嵌套函数,下面列举一例:
|
|
函数的调用由内层层到外,所以即便内外函数名以及参数类型列表彼此相等,函数内也是优先调用内部函数;
为指定形参进行传参
也就是说,如果在传入参数的过程中,指定了要赋值给哪一个参数,那么就可以不按照原本的顺序传参,看下面的实例:
|
|
输出为:
|
|
可见虽然传入的参数依次是10、21、3,但是由于指定了要赋值给哪一个参数,所以a、b、c分别为21、10、3;
Vararg参数
在Java中,该功能底层是通过数组实现的。Scala的书写与Java有差别,采用的是参数类型后面添加*,此后不能再跟非Varalg参数,下面用一个例子说明:
|
|
类型参数(Scala泛型)
这里要讨论的实际上就是Scala中的泛型,基本的格式如下:
|
|
Java中泛型的作用不必多言,如果不用泛型采用Any,最后进行类型转换凑合使用:
|
|
采用泛型来重写ide函数:
|
|
此时再调用ide函数将不需要显示转换类型:
|
|
也可以写成val ss: String = ide[String]("Hello")
,但是即便不写上类型,Scala可以通过类型推导得出正确的类型;
小结
“参数组”和“方法调用”因为和后续内容有关,本篇没有涉及。本篇主要探讨了Scala函数书写的形式和用法,每个小节都多少和Java相关内容进行了类比。