初识Scala
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类型, 加
L
或l
后缀为Long类型, 支持10进制和16进制写法,8进制写法已被废弃.
示例:123
,0xFF
,123L
-
浮点字面量: 默认为Double类型, 加
F
或f
后缀为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重命名为_
, 然后该名称被覆盖达到了隐藏某个类的效果。