Scala和Kotlin、Clojure等一样是一种jvm语言,传说其复杂度可与C++一较高下。用下来感觉并不舒服,例如其中的implicit特性,能够减少很多代码的冗余,但另一方面,又会导致代码对新手而言的可读性变差。
这篇文章拆分自我从前的文章《使用Scala进行Spark-GraphX编程》。
括号
通常,小括号()表示表达式和函数调用,大括号{}表示代码块。例如在.map({})中的大括号即表示一个代码块。特别地,代码块也是一个表达式,所以下面的代码也是成立的
1( { var x = 0; while (x < 10) { x += 1}; x } % 5) + 1
同时,括号也是可以省略的。根据Scala Style Guide,在Scala中,一个无参方法在调用时可以省略小括号。这里注意,如果函数带一个是隐式参数或者默认参数,那么就不能带空括号。
那么如何区分obj.attribute是字段还是方法呢?对此,Scala有统一访问原则(Uniform Access Principle, UAP),也就是指代码不因为属性是通过字段实现还是方法实现而受影响。因此实际上Scala只有两个命名空间,类型和值。
容器
Array/Seq/List
这三个都可以表示线性表,那么他们的区别是什么呢?
首先,Array实际上明确对应了Java里面的数组。例如下面的代码的返回值就是int[]。
1Array(1,2).getClass.getSimpleName
在Java中,我们显然不会把原生数组和容器类型搞混,那么为什么在Scala中,我们就会有这样的困惑呢?原因是
Implicit
在Scala中,可以通过implicit关键字修饰方法/变量、参数、类,对应实现隐式视图和隐式参数。其中隐式视图和隐式参数可以对应到泛型约束中的视图界定和上下文界定。
隐式视图
隐式视图可以实现隐式Casting。如下面的代码所示,错误的原因是没有办法将Double转为Complex,所以和其他例如C++等语言类似,这里需要一个隐式转换。
1
2
3
4
5
6
7
8
9
10
11
12
13
14case class Complex(r: Double, i: Int){
def +(c: Complex) = Complex(r+c.r, i+c.i)
def +(d: Double) = Complex(r+d, i)
override def toString() = r + "_" + i
}
val c = Complex(1, 2)
println((c + 1).toString()) // 2.0_2
println((1 + c).toString()) // Error
println(Complex(1, 0) + c) // OK
// 视图绑定要求t能够隐式转换为Complex
def printComplex[T
printComplex(1.0)
如下所示,implicitConvert负责Double到Complex的隐式转换
1implicit def implicitConvert(x: Double) = Complex(1.0, 0)
此外,隐式视图还可以使用目标类的方法来扩展原类的方法。
隐式参数
首先,Scala提供默认函数值,如
1
2
3def addInt(a: Int, b: Int = 1) : Int = {
return a + b
}
但另一种机制implicit parameter会更为灵活。implicit parameter的用法如下面所示,我们可以为类型Pe