Scala语言特点以及技巧

王大磊
6 min readJan 13, 2017

--

Scala作为一个运行与JVM之上的语言,融合了面向对象的特性和函数式的特性,整体语言设计比较学术,核心语法风格优雅而统一,并且只有比较少的保留字符,大部分符号都可以重新定义,具有相对比较灵活的语法特征。

作为从Java开发转过来的开发者,Scala能带来以下几个好处:

  1. 开发效率的提升,Scala语言的设计很优雅,语法表达能力很高,结合函数式特性,通常一行就能表达所做的事情,而不像面向对象或者面向过程,需要一段代码来表达做了一个什么事情,尤其是集合的写法,通过Function literal在集合函数的应用来替代For循环等语句,更加紧凑高效;
  2. 稳定性,由于更多的使用不可变的声明,代码运行更加不容易出现不可预料的异常,同时函数式的应用也可以增加运行的稳定性
  3. 运行效率的提升,由于函数式在开发过程大量应用,使得程序在运行时能够更好的利用多核来处理,更容易编写并发的程序,并发更稳定。
  4. 程序接口的设计更优雅,由于更少的关键字,很多符号可以重新定义,可以自己定义的新的语法树,在不同的领域表达不同的概念,可以组织可读性更好的API,比如图相关的API,a ~> b,代表两个节点相连接,虽然增加了不同库的学习难度,每个lib的学习就像一个新的语言,但带来了可读性和易用性的提升,同时也减少了使用出错的几率,对其他协作开发的同事或者用户更友好。

对于从Java语言转过来的开发者,并没有想象中那么容易,主要有以下几个概念或者说理念上的差异:

  1. 变量声明的区别
    在Scala语言里,声明变量有两种形式,一种是var,一种是val,前者代表其引用是可变的,后者不可重新赋值,同时在Scala中存在两组并行的Collection的定义,对集合的内容是否能够进行修改也有区分,有mutable和imutable的区别,从这个角度我们也可以看到,Scala语言非常在乎变量或者引用是否能够被修改,通过定义杜绝了变量的非预期的修改,更多的以函数式的思想去考虑问题,增强代码逻辑执行过程的稳定性和准确性。
  2. 类型推断
    在Scala语言里,一个上下文里边的类型都可以传递下去,一般情况不需要写变量的类型,虽然不写具体的类型,但是Scala是一种强静态类型的语言,编译器会严格的检查变量所在的区域具体的类型,是否是所需要的,能不能执行所调用的操作,可以在编译过程中发现很多问题;
  3. 函数式的概念
    借鉴Haskell, 函数在Scala里边也是一等公民,可以跟变量一样赋值、传递、修改等,并且支持高阶函数,让函数的使用和定义更加灵活,支持函数式对多核领域有很大的优势,由于纯函数式的输入输出稳定性,可以方便的把函数分发到不同的核心去运算而不用担心出现互相影响,在编译时可以优化运行时对多核心的利用,提高运行效率,但Scala并不是纯函数是语言,不如纯函数严格,允许函数有Side effect,Curried function也只是高阶函数的简化形式,不是所有的函数都可以当高阶函数使用,好处在于Scala里边的函数与面向对象的概念很好的结合起来,可以认为函数就是一种对象,使用函数跟Object差不多,不同的函数继承自不同的对象,打通了面向对象和面向函数的概念。
    同时函数式对多核编程友好,可以更可靠的利用多核心的并发能力,可以说面向对象倾向于是对世界的模拟,适合用在工程抽象,而面向函数就是更偏向纯数学的定义,适合对事物做抽象,而且函数式的代码运行更稳定可靠,不会对上下文产生Side effect,适合算法和核心逻辑的编写。
  4. 交互式编程和声明式表达能力的区别
    传统的编程语言不管是面向过程还是面向对象,其最核心的处理流程依然是交互式的,通过编写一个block的代码来完成某个功能或者某个对象的行为,构成这一段代码的所有变量以及计算过程互相影响,要想了解这段代码做了什么需要按顺序自己模拟下执行过程,而函数式语言虽然也是由一行行的代码构成,但更着重于声明式的表达,倾向于一行表达一件事,比如在scala中所有的语句都是表达式,都有返回值,包括if for等传统的控制语句,都不是为了表达一个过程,而更着重于声明表达,并将表达式的值赋值给某个变量或函数,所以阅读函数式代码,通常是一层一层函数或者表达式深入下去,如果不关注具体的实现只要看最外层那一行就能够了解其做了什么。
    在scala中有很多语法糖,包括把某个操作符作为中置表达式,通过空格分开而不是.,这些都有助于构造声明式的表达,所形成的程序更直接可读性更好。一个个的定义构成了函数式语言所完成的功能。
  5. 隐式
    scala语言的隐式转换有优势也有一些缺点,一般情况隐式转换大大提高了语言的表达力。省略了很多繁琐的代码的编写,使得scala语言通常比java代码短。主要的两个优势,其一是在函数式调用中尤其是柯里化的函数,减少参数的输入,使用上下文的隐式声明更方便,其二是增加了库的扩展性,比如普通的string具有的toInt方法就是通过隐式转换实现的,本来string并没有这个方法,当代码里边出现这个调用的时候,编译器会去看这个类有没有这个方法,如果没有就从上下文去找这个类的隐式转换,然后检查转换后的类有没有这个方法,而在scala中string可以被隐式转换为StringLike,里边有大量的转换方法,遇到这种需求不再需要自己调用转换方法,就想String本来就有这个方法一样,非常方便且无缝完美的扩展了原来的某个类。
  6. Generic类型界限以及协变逆变
    在Java代码里泛型是可以在很多位置声明,但Scala的泛型更灵活,限制也更多,使泛型的应用更准确,副作用更小。泛型的界限包括了上限下限(<: >: 继承关系),视图界限(<% 隐式转换关系),上下文界限(A:T 上下文存在隐式T[A]类型定义)。
    协变逆变限制了在扩展泛型类时,所传入的类的继承方向,一般类的泛型是协变而方法的参数类型是逆变。
  7. 元编程能力
    Scala的语法非常灵活强大,可以自己定义一种新的语法,自己组织AST和编译过程。目前Scala Meta可以替代原来很难用的Reflect包,后者实在是太繁琐了,如果跟Java的反射一起用更是麻烦。纯粹的元编程能力,scalameta要简单强大很多。
  8. 灵活的语法特点增加代码的表现力的同时也增加了第三方库的额外的学习成本

公司现在已经使用Scala语言开发两年了,同时也使用了java8,目前看来大家对Scala接受程度和使用上都比较满意,相对于Java 8 那种狗尾续貂的新特性,兼容原来语法的各种妥协,Scala要统一优雅的多,作为一个从一开始就很学院派的语言,其设计风格统一而准确。将面向对象和函数式编程完美的结合在一起,生产力有提高。缺点就是依然是基于JVM对本质上性能提升没有任何帮助,有可能还比直接的Java代码要慢。

编程语言类型座标

--

--