1. 基础部分
1.1 变量
scala的变量定义主要分为以下三类:
- val: 修饰不可变的常量
- var: 修饰变量
- lazy val:修饰延迟加载的常量
PS:scala支持类型推导,可以不加类型指定。
下面演示三种例子:
1.2. scala类型体系
scala类型主要分为值类型和引用类型。注意null是引用类型的空值,unit是值类型的空值(字面量就是一对小括号),nothing是所有类型的空值
这里顺带提一下scala自带的String"插值"特性:
1.3 函数与代码块
注意点如下:
- 同一行多个表达式用分号分隔
- 函数的最后一行表达式是返回值
- 只有一个表达式,或括号可以省略。例如:
1.4 if和for表达式
if和for都是表达式,最后都可以得到一个结果
1.5 try-catch-finally
PS:下划线是通配符,通配所有的对象
1.6 match表达式
类似java的switch case
例子:
2. 求值策略——call by name & call by value
scala中所有的运算都是基于表达式的。所以这里要说下表达式的求值策略:
PS: 一般都是用call by value为主
- call by value: 先对实参进行求值
- call by name: 先对实参不求值,类似C语言的#define,只是传递过去一个name ,用的时候再求值(有点惰性求值的感觉)。
参考例子:
总结:可见,有时候表达式比较复杂,又经常使用的话,使用call by name会重复做很多次运算,会浪费资源。但是表达式很简单,就一个值,使用call by name会节约时间。不过这种优化估计提升不多,一般还是用call by value吧
3. 高阶函数
3.1 函数与匿名函数
scala的函数是第一等公民。所以函数本身支持以下特性:
3.1.1 函数类型
函数类型:
3.1.2 高阶函数
高阶函数:
3.1.3 匿名函数
匿名函数:
匿名函数例子:
3.2 柯里化
为什么使用柯里化函数?:
scala高阶函数和柯里化一文演示了柯里化函数如何使得函数的使用更加简洁高效。
为什么使用柯里化函数?(转自知乎):
柯里化理论上非必须, 实际上是必须的. 科里化本质是用单参数的函数拼出多参数的函数, 这样拼出来的函数有个特点就是只接受部分参数时是另外一个函数. 这对函数式语言来说太重要了, 可以简化一大堆东西. 当然,如果所有函数式语言都不支持科里化,其实世界照转, 只是你需要在自己代码里面变相地\不完全的\带着bug地\重复地实现科里化...
作者:Syeerzy Z
链接:https://www.zhihu.com/question/20037482/answer/38180038
下面同学给出的例子可以看到,使用柯里化避免了在函数中调用函数时带来的麻烦,即再命名一个函数。通过柯里化,可以让把原来的函数剥离成只接受一个参数的函数,单独拿来使用。因此,这大大简化了编程的复杂度。
3.3 递归与尾递归
scala实现循环本质都是采用递归(虽然有for表达式,但是其本质也通过递归实现)。
scala是支持尾递归的。
可见,尾递归有效避免了栈溢出,提升了递归的效率。
综合例子:
使用尾递归+柯里化
4. scala immutable collection
4.1 List
只接受同一个类型
获取元素也可以直接使用索引,即a(0)表示获取a这个List的第一个元素
要遍历List可以采用递归函数来遍历:
4.2 使用集合的filter、takeWhile、map、flatMap方法
filter和takeWhile方法的使用如下
map方法演示
4.3 集合的reduceLeft、foldLeft
例子:
PS: 这里a = List(1,2,3)
可以看到foldLeft使用了柯里化
PS: 这里a = List(1,2,3)
4.4 Range和Stream
4.4.1 Range
4.4.2 Stream
Stream是一个惰性的列表,用#::来连接
例子:
4.5 tuple
tuple是集合,可以存放不同类型的元素,区别于List。可以直接通过下划线+位置的方式来获取元素
4.5 map
删减1个元素或者删减多个元素(多个元素封装在List中)
综合例子——实现快速排序