初识Scala

时间:2021-06-10 07:45:51

scala 是 scalable Language 的简写,是一门多范式的编程语言. scala是一种纯面向对象的语言每个值都是对象, 同时支持大量的函数式特性.

scala运行于Java虚拟机(JVM)之上, 并依赖和支持大量Java包。搭建scala运行环境时需要首先安装Java运行环境.

scala拥有交互式方式和脚本两种执行方式,命令行提示符为scala>, 脚本通常以.scala作为后缀名.

scala的语法与Java类似, 但以以换行或分号标志语句的结束,使用花括号{}标志代码块, 语义与缩进无关, 禁止使用\将一行语句拆为多行(\是合法的scala标识符).

scala支持//引导的单行注释, 和/*, */引导的多行注释。

在Linux和OS X系统上可以使用包管理器安装scala:

apt-get install scala
brew install scala

在命令行输入scala命令进入scala交互环境:

scala> println("Hello World")
Hello World scala> 1 + 1
res5: Int = 2

编写脚本Hello.scala

object HelloWorld {

   def main(args: Array[String]) {
println("Hello World!")
} }

在终端中编译执行:

$ scalac hello.scala
$ ls
HelloWorld$.class HelloWorld.class hello.scala
$ scala HelloWorld
Hello World!

scala源文件与Java一样, 所有的语句均包含在对象内。编译完成后每个类会生成独立的class文件。类中的main函数为执行的入口函数。

scala 数据类型

标识符区分大小写,以字母或_$开头, 后续字符可以为数字,字母或_$. $开头的标识符通常为内置标识符,应尽量避免以$开头. _ 为scala保留字, 不能单独作为标识符.

我们可以在``之间使用任何有效的 scala 标识符, 一个典型例子为 Thread 的 yield 方法, 因为 yield 为 scala 中的关键字, 无法使用Thread.yield()必须使用 Thread.`yield`() 来使用这个方法.

在 scala 中,使用关键词 var 声明变量,使用关键词 val 声明常量. scala为静态强类型语言, 变量类型一旦声明无法更改.

scala> var a = 1
a: Int = 1
scala> var b:Int = 2
b: Int = 2

scala的局部变量必须在声明时指定初值, 只有类属性可以只声明类型不指定初值.

如示例中第二条语句,在声明时中可以使用: Type指定变量类型, 在大多数情况下编译器会根据初值自行推断类型。

scala支持多变量同时声明和声明元组:

scala> var (x, y) = (0, 0)
x: Int = 0
y: Int = 0
scala> var x, y = 0
x: Int = 0
y: Int = 0

scala内置的类型包括:

  • Byte: 8位有符号补码整数。数值区间为 -128 到 127

  • Short: 16位有符号补码整数。数值区间为 -32768 到 32767

  • Int:32位有符号补码整数。数值区间为 -2147483648 到 2147483647

  • Long: 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807

  • Float: 32位IEEE754单精度浮点数

  • Double: 64位IEEE754单精度浮点数

  • Char: 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF

  • String: 字符序列

  • Boolean: true或false

scala中还有一些特殊的类型:

  • Null: null 或空引用

  • Nothing: 任何其他类型的子类型。

  • Any: 所有其他类的超类

  • AnyRef: 所有引用类(reference class)的基类

scala定义了一些字面量的语法:

  • 整型字面量: 默认为Int类型, 加Ll后缀为Long类型, 支持10进制和16进制写法,8进制写法已被废弃.

    示例: 123, 0xFF, 123L

  • 浮点字面量: 默认为Double类型, 加Ff后缀为Float型.

    示例: 2.718, 2.718F, 1F, 2D, -1.2

  • 字符字面量: 一对单引号包括的单个字符, 支持转义字符, 也可以用可以使用4位16进制数表示

    示例: 'a', '\n', '\u0038'

  • 字符串字面量: 一对双引号包含的字符串, 支持转义字符:

    示例: "Hello World\n"

  • Null与逻辑值: null, true, false

  • 符号字面量: scala.Symbol的简写, 使用'引导一个标识符。

    示例: 'a 等价于 scala.Symbol("a")

scala的运算符系统与Java非常类似, 保留了位运算符,取余%以及复合赋值,但是不支持++--

赋值运算返回Unit, 不支持连续赋值。

流程控制

Scala的流程控制与Java基本相同。

if

if (score > 80) {
rank = "excellent"
}
else if (score > 60) {
rank = "good"
}
else {
rank = "fail"
}

while

while (i <= 100) {
s += i;
i += 1;
}
do {
s += i;
i += 1;
} while (i <= 100);

for

scala 的for循环很独特值得一提.

scala> for (i <- 1 until 10) { println(i); }
1
2
3
...
9

until不包含结尾数字, to则包含结尾数字.

scala> for (i <- 1 to 10) { println(i); }
1
2
3
...
10

for 循环同样可以用来遍历集合:

scala> var arr = List(1, 2, 3, 4)
arr: List[Int] = List(1, 2, 3, 4) scala> for (i <- arr) {println(i);}
1
2
3
4

可以设置多个循环变量和循环域, 从而简化嵌套循环的语法:

scala> for (i <- 1 to 2; j <- 1 to 3) { print(i); println(j); }
11
12
13
21
22
23

for 循环中可以嵌入条件判断:

scala> for (i <- 0 until 5 if i % 2 == 0;if i != 0) { println(i) }
2
4

yield关键字与for循环搭配可以生成容器, 首先需要认识到for循环是有返回值的:

var r = for (i <- 1 until 3) {}
r: Unit = ()

yield关键字可以将一个表达式的返回值填入返回的容器:

var r = for (i <- 1 until 3) yield i
r: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2)

break, continue

谢谢, scala中并没有这两个关键字. 我们需要使用if语句和标记来代替它们的功能.

模式匹配

scala模式匹配提供了类似于switch的流程控制:

scala> val s = 'B';
s: Char = B
scala> s match {
| case 'A'=> "Apple"
| case 'B'=> "Bravo"
| case 'C'=> "Company"
| case 'D'=> "Delta"
| case _ => "..."
| }
res15: String = Bravo

当s与match中的某一个case匹配时, match语句即返回case对应的值.

自定义case class可以定义样例类代替内置类型进行模式匹配.

包管理

scala采用与Java类似的包管理机制,将package语句放在文件头声明文件中所有类都属于该包:

package pw.finley

或者声明:

package pw.finley {
class Hello;
}

scala 使用 import 关键字引用包, scala可以*引用java包:

scala> import java.awt.Color  // import class Color

scala> import java.awt._   // import all classes in java.awt

scala>

import语句可以出现在任何地方,而不是只能在文件顶部.

import的效果从开始延伸到语句块的结束, 这可以大幅减少名称冲突的可能性.

import可以引入多个指定的类, 并可以对引入的类重命名:

scala> import java.awt.{Color, Font}  // import several classes

scala> import java.util.{HashMap => JavaHashMap}  // rename class

import java.util.{HashMap => _, _}  // hide specific class, HashMap has been override by _

最后一个示例中将HashMap重命名为_, 然后该名称被覆盖达到了隐藏某个类的效果。