学习Scala: 初学者应该了解的知识

Scala开发参照清单

这里列出在开发一个Scala工程中需要参照的资料。

官网网站

http://www.scala-lang.org/

文档网站

http://docs.scala-lang.org/index.html

Cheatsheet

http://docs.scala-lang.org/cheatsheets/

代码风格

http://docs.scala-lang.org/style/

设计模式

https://wiki.scala-lang.org/display/SYGN/Design+Patterns

Language Specification

http://www.scala-lang.org/files/archive/spec/2.11/

API

http://www.scala-lang.org/api/current/#package

Scala wiki

https://wiki.scala-lang.org

Scala Tools and Libraries

https://wiki.scala-lang.org/display/SW/Tools+and+Libraries

Scala的初次约

Scala是由Martin Odersky设计的一种结合了函数式编程(不仅仅有这个)的强类型语言。 Scala的代码会被编译成Java bytecode,并在JVM上运行的。 可以认为Scala是Java的扩充,一个Java语言的超集。 Scala的设计思想之一,来自于对Java语言的一些缺点的批评。

个人也觉得Java语言发展的太慢,尤其是和C#、.NET相比。 Scala的横空出世,提供了一个积极性的灵感,解决了Java语言的发展问题,给Java社区带来强大的活力。

Scala的优势

  • Java有的优势,Scala都有
  • Scala的编程风格更简洁 Scala的简洁风格,也很可能降低可读性。所以在团队开发中,还是需要一个良好的代码规范来约束。
  • 性能很好 和Java的性能一样,比Python快的太多了。
  • 可以直接使用Java类库。
  • Java也可以使用Scala的类库。 个别情况下,需要在Scala里做特殊的支持。

Scala的用途

  • 结合Spark,处理大数据。 这是,目前,Scala的一个主要应用。Spark也是那Scala写的。
  • Java的脚本语言版 可以直接写Scala的脚本,也可以在.sh直接使用Scala。
  • 代替Java。 scala希望提供一种简洁的语言。不过作为初学者的我,scala极其容易导致代码的可读性比较差。 Java语言还是有其优势。

Scala的代码风格

由于Scala结合了函数式编程和面向对象语言特征,从这个方面看,有两种编程风格可以选用。

  • 支持函数式编程的面向对象编程风格
  • 函数式编程风格

如果你开发的项目主要用于处理数据,函数式编程风格更适用。 本文也主要针对函数式编程风格。

安装scala

可以从scala的官方网站上下载。 许多人会选择Intellij IDEA或者Eclipse作为scala的编辑器。

这里有个使用Visual Studio Code作为编辑器的介绍: Scala on Visual Studio Code

函数式编程到底意味着什么

请参考:函数式编程 : 一个程序猿进化的故事

Scala的再认识

trait, class,object

开始学习Scala会看到trait这个奇怪的词,而且可以def object。这里解释一下: trait: 类似于Interface,不过可以实现声明的方法。 class: 就是class. object: 就是Module,一个静态类。

Scala的语言特征

除了Java的语言特征外,Scala还提供了一下主要特征。 (这个章节比较深奥,可能不足,需要慢慢地更新)

函数式编程(functional programming)

上面已经说过了。

类型推测(typing inference)

这个特征C#也有。建议大家尽量使用这个特点。也就是说

  • 避免定义变量的数据类型 一个好处是类型发生变化的时候,改动的代码会相对较少。
  • 对于函数,要定义输入和输出的数据类型。

implicit特性

我把对implicit的认识分为这几个Levels。

Level 0: 完全忽略implicit的存在

如果,你在你的项目里发现有人使用implicit,可以理直气壮地批评,这是降低可读性的杰作。 implicit特性应该避免被使用。implicit很可能给读代码的人带来困惑,属于反直觉的代码。

Level 1:简单的认识implicit conversions

比如:一个函数的参数的Long型,调用时输入一个Int型的数据,也不会出错, 其后面就是implicit conversions功劳。 implicit conversions逻辑发现类型Int/Long不匹配, 然后在一个implicit view(可以看成一个函数pool,包含了所有的implicit functions)中找一个输入为Int,输出为Long的函数, 最后通过这个函数完成类型的转换。 Scala自身提供了一些必要的implcite conversion functions.

Level 2: 对implicit的有个基本理解

implicit的使用

使用起来很简单,直接把implicit关键字,加到trait/class/object/def/val之前就可以。 在Scala 2.10版后, implicit可以用在三个地方: 例如:

  • implicit functions vs implicit conversions implicit def int2ordered(x: Int): Ordered[Int] = new Ordered[Int] { /* .. */ }
  • implicit classes implicit classes是针对Pimp-my-library pattern,在Scala语法上的实现。 这个和C#的extesion methods的用意是一样的。 比如,你想在Scala的List类上,增加一个函数,而不用去修改Scala的发布包, 在Scala 2.10版以后,就可以通过implicit classes实现, 之前的版本,可以通过Pimp-my-library pattern实现。 在下面这个例子中,如果import Helpers._,类IntWithTimes的所有方法都会作用于Int上。 object Helpers { implicit class IntWithTimes(x: Int) { def times[A](f: => A): Unit = { def loop(current: Int): Unit = if(current > 0) { f loop(current - 1) } loop(x) } } }
  • implicit values vs implicit parameters 来自官方的一个例子:
object ImplicitTest extends App {
  /** 
   *  To show how implicit parameters work, 
   *  we first define monoids for strings and integers. 
   *  The implicit keyword indicates that the corresponding object can be used 
   *  implicitly, within this scope, as a parameter of a function marked implicit. 
   */
  implicit object StringMonoid extends Monoid[String] {
    def add(x: String, y: String): String = x concat y
    def unit: String = ""
  }
  implicit object IntMonoid extends Monoid[Int] {
    def add(x: Int, y: Int): Int = x + y
    def unit: Int = 0
  }
  /** 
   *  This method takes a List[A] returns an A which represent the combined 
   *  value of applying the monoid operation successively across the whole list. 
   *  Making the parameter m implicit here means we only have to provide 
   *  the xs parameter at the call site, since if we have a List[A] 
   *  we know what type A actually is and therefore what type Monoid[A] is needed. 
   *  We can then implicitly find whichever val or object in the current scope 
   *  also has that type and use that without needing to specify it explicitly.
   */
  def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
    if (xs.isEmpty) m.unit
    else m.add(xs.head, sum(xs.tail))
  /** 
   *  Here we call sum twice, with only one parameter each time. 
   *  Since the second parameter of sum, m, is implicit its value is looked up
   *  in the current scope, based on the type of monoid required in each case, 
   *  meaning both expressions can be fully evaluated.
   */
  println(sum(List(1, 2, 3)))          // uses IntMonoid implicitly
  println(sum(List("a", "b", "c")))    // uses StringMonoid implicitly
}
implicit的功能可以分为两类:
  • implicit conversions (from implicit functions and implicit classes) 当Scala发现类型不匹配,或者正在调用一个对象不存在的函数时, Scala compiler就会去implicit function list中找一个匹配的函数。
  • implicit arguments (from implicit values and implicit objects) 在函数上可以定义一个implcit参数,编译器会在implicit的对象列表中, 找到一个类型匹配的对象,并传入。
作用域

可以想到,implicit有个作用域。这个作用域,和当前的package,以及import的类, 还有Scala的默认有关。

Level 3: 重申:避免使用implicit

Level 4: 如果要使用implicit

  • 好好阅读关于implicit作用域,编译器的查找complicit对象的顺序等知识。
  • 定义implicit的开发规范
  • 写好文档帮助开发人员和用户理解。
  • 限制其使用的场景
    • 你要实现一个类似于虚数这样的新数据类型。
    • ...

Collection

请看Scala Collection简介

Mutability vs Immutability

可变的变量(Mutable variables)(主要是可变的对象)会引起一些潜在的问题:

  • 变化后,可能在map中找不到了
  • 性能损失(在多线程下,读写需要加锁)

编程方面的建议是:

  • 如果可能,使用和开发 immutable 类。

杂七杂八

_ 的用途

请请看Scala underscore的用途

Null, null, Nil, Nothing, None, and Unit

  • Null是Scala中的一个Trait.
  • null是一个Null的实例,相当于Java中的null。在面向函数编程中,不要使用,用None代替。
  • None是一个None.type的实例,代替null。 在一个函数中,用于表达这个函数返回了没有值。可以避免 null pointer exception。
  • Unit是Scala中的一个类型,用于表示一个函数没有返回值。 有点像Java中的void,不过其实返回了'()'。
  // There is no '=' before '{', so the function return Unit.
  def funUnit(x: Int) {
    x * x
  }

  // There is a '=' before '{', 
  // so the function returns the value of the last expression.
  def funReturnLastStatement(x: Int) = {
    x * x
    x + x
  }

  // Recommend to use explicit return type, and = forever.
  def funReturnLastStatementGood(x: Int) : Int = {
    x * x
    x + x
  }
  • Nil 是一个空的List实例.
  • Nothing是Scala中的一个Trait。基本上没有用。(我猜的)

## 和 == 对 equals 和 hashCode

在Scala中, ##方法相当于Java中的hashCode方法。 ==方法相当于Java中的equals方法。 建议使用##和==,因为Scala针对value类型实现额外的功能。

Generic classes/functions: +T, -T, <:, >:, <&

  • +T: 作用于class, 用于协变(covariant)
  • -T:作用于class, 用于逆变(contravariant) +T, -T 作用于泛型对象之间赋值。
  • T <: A: 作用于 function, 约束:T是A的子类,也称作upper type bound,这是一个协变。 一般会和-T合用。
  • T >: A: 作用于 function, 约束:T是A的超类,也称作lower type bound,这是一个逆变。 一般会和+T合用。
  • T <& A: 作用于 function, 约束:存在一个T => A的implicit conversion,也称作view bound. <:, >:, <& 作用于泛型函数之间赋值。

请看不变(Invariant), 协变(Covarinat), 逆变(Contravariant) : 一个程序猿进化的故事

编译.scala文件到jar文件

scalac -d test.jar D:\project\*

参照

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏五分钟学算法

看完动画你还会不懂 快速排序么

由于LeetCode上的算法题很多涉及到一些基础的数据结构,为了更好的理解后续更新的一些复杂题目的动画,推出一个新系列 -----《图解数据结构》,主要使用动画...

22350
来自专栏前端下午茶

JS 原型模式

原型模式(Prototype pattern),用原型实例指向创建对象的类,使用于创建新的对象的类的共享原型的属性与方法。

41610
来自专栏IT派

程序员必知的 Python 陷阱与缺陷列表

我个人对陷阱的定义是这样的:代码看起来可以工作,但不是以你“想当然”的方式。如果一段代码直接出错,抛出了异常,我不认为这是陷阱。比如,Python程序员应该都遇...

12840
来自专栏Phoenix的Android之旅

说一个小bug

这个bug其实很简单,因为String是不可变内容的,想获得新值,必须重新赋值。正确应该是

10830
来自专栏aCloudDeveloper

一个交换程序的通用版本

Author:bakari   Date:2012.9.3       交换程序是每个开始学习编程的人必学习的一个初级算法。算法思想很简单,就是为两个交换的双方...

17960
来自专栏微信公众号:Java团长

JAVA之旅(一)——基本常识,JAVA概念,开发工具,关键字/标识符,变量/常量,进制/进制转换,运算符,三元运算

比如6:6/2 = 3 余 0 3 / 2 = 1 余 1 那就是从个位数开始011,读起来就是110了

19410
来自专栏编程

您真的会用switch吗?

C语言的理念,程序员应该知道自己正在干什么,而且保证自己的所作所为是正确的。 switch知多少 各个case和default的顺序可以是任意的,但习惯上总是d...

22270
来自专栏老司机的技术博客

宝宝都能学会的python编程教程16:map和reduce

如果你学习过大数据相关知识一定不会陌生MapReduce。 如果你没有学过大数据,也没关系,本文将带你了解python的map和reduce函数。 map()...

37750
来自专栏轮子工厂

卧槽,为什么你的程序执行到一半就退出了,原来是因为加了这个

快到月底了,相信有很多人都和呆博一样,不是“快揭不开锅了”,而是已经快要把锅都吃了〒▽〒。没关系我们可以一起吃掉这篇精神食粮啊,营养又健康,如果觉得味道还不错,...

32320
来自专栏轮子工厂

8. 一花一世界,while for 循环?

wo这周有点懒啊,这才第 2 篇,个人有点事情,本来预计可以更新……1 篇的,︿( ̄︶ ̄)︿

13320

扫码关注云+社区

领取腾讯云代金券