Scala名称是scalable language,表明可扩展性较强
- 面向对象编程和函数式编程的结合
- Scala代码被编译成Java字节码,运行在JVM上,可以调用已有的Java代码
- 方便进行并发和同步处理
面向对象
任何值都是一个对象,任何操作都是一个方法调用
1 + 2//实际上是:Int类调用+方法
函数式语言
- 函数是 first-class values,就像int和String类型,可用作为其他函数的参数,返回值,可以赋值存储在变量中
数据,函数,类等的类型分为三类
First Class 该类型的值可以作为函数的参数和返回值,也可以赋给变量。
Second Class 该类型的值可以作为函数的参数,但不能从函数返回,也不能赋给变量。(C/C++ 中的函数指针)
Third Class 该类型的值作为函数参数也不行
- 输入值处理后映射到新的输出值,不改变原数据,即不可变数据结构(immutable data structure),或者说方法不产生副作用,即引用透明(reference transparent)
副作用:side effect,改变方法外部的的变量状态或者执行I/O操作,返回值为空的函数都有副作用,副作用是不可避免的,但是可以尽可能的减少此类函数
特点
- 兼容性
Scala可以和Java无缝对接,调用Java的方法,访问字段,继承类,实现接口等,不需要其他的语法,Java代码也可以调用Scala代码
重用了很多Java的类型,也对一些类型进行了增强,通过隐式转换来实现扩展的高级操作和Java原有操作的兼容 - 简洁
Scala是同样的Java代码行数的一半左右
避免了一些样板式的语法,类型推断减少了重复的类型信息,大量的库代码可以直接使用,特别是traits,便于构建一个类
// Java 类定义
class MyClass {
private int index;
private String name;
public MyClass(int index, String name) {
this.index = index;
this.name = name;
}
}
//等同的Scala类定义
class MyClass(index: Int, name: String)
- 高阶 high-level
//name中是否包含大写字母
val nameHasUpperCase = name.exists(_.isUpper)//_.isUpper是函数字面量,或者叫做匿名函数
//Java 8中的写法
boolean nameHasUpperCase =
name.chars().anyMatch(
(int ch) -> Character.isUpperCase((char) ch)
);
可以使用其他函数作为参数,轻量,容易理解和重构,引用透明
s.exists(p) || s.exists(q) 等价 s.exists(x => p(x) || q(x))
- 静态类型
指在编译时进行类型检查
Scala的类型系统通过类型推断避免冗长,通过模式匹配以及其他几种新方法保证灵活性
属性验证:静态系统通过类型检查,避免某些运行错误,减少需要类型检查的次数
安全重构:修改代码,正确率更高,例如更改函数名称,修改参数等
文档:编译器和IDE可以提供更多的帮助,例如根据类型进行代码提示
起源
Scala采用了大量的Java和C#语法,他们大部分又来自C和C ++的语法。 表达式,语句,块,类,包和导入等语法大都类似Java,同时Scala也采用了Java的基本类型,库及其执行模型等。此外也借鉴了许多其他的语言,例如Ruby,Algol,Simula,ML等
同时Scala也有自己的创新,例如抽象类型abstract types,特质traits,提取器extractors等
语法概览
定义变量
有两种类型的变量val
和var
, val
类似于Java中的final
变量, 一旦初始化,不能被重新赋值,
var
可以重新赋值
Scala的解释器或编译器可以推断类型
scala> val msg = "Hello, world!"
msg: String = Hello, world!
scala> val msg2: java.lang.String = "Hello again, world!"//显式指定类型
msg2: String = Hello again, world!
定义函数
函数开头是def
关键字,之后是函数名,圆括号内是通过逗号分隔的参数列表,参数的类型必须指定(不会进行类型推断),冒号后跟返回类型,之后是等号后跟一对花括号,内部是函数体(函数相当于返回一个数值的表达式块)
def max(x: Int, y: Int): Int = {
//Scala的 if 语句可以返回一个值
if (x > y)
x
else
y
}
函数参数类型是val
,不能重新赋值
返回类型可以推断时,可以省略,没有返回值对应Unit
类型(Java中的void
类型)
函数只有一条语句,花括号可以省略
匿名函数
也叫作函数字面量(function literal),通常作为函数的参数进行传递
//功能相同的遍历打印语句
args.foreach(arg => println(arg))
args.foreach((arg: String) => println(arg))
args.foreach(println) //对应函数为带一个参数的一条语句
for (arg <- args)
println(arg)
数组
访问数组中的元素,索引放在圆括号内,val
类型的数组本身的内容是可变的
val greetStrings = new Array[String](3)
//初始化每个元素
greetStrings(0) = "Hello"
greetStrings(1) = ", "
greetStrings(2) = "world!\n"
for (i <- 0 to 2)
print(greetStrings(i))
//等价于
greetStrings.update(0, "Hello")
greetStrings.update(1, ", ")
greetStrings.update(2, "world!\n")
for (i <- 0.to(2))
print(greetStrings.apply(i))
0 to 2
对应方法调用 (0).to(2)
,如果方法只有一个参数,则可以不带圆点或圆括号,但是必须指定方法调用的调用方
Scala没有运算符重载,因为它实际上并没有传统意义上的运算符,但是可以在方法名称中使用
+, -, *, /
等字符
访问:将包含一个或多个值的括号应用于变量时,Scala会将代码转换为调用该变量名为apply
的方法
赋值:当对包含圆括号的变量进行赋值时,编译器会将其转换为update
的方法,该方法将括号中的参数以及等号右侧的对象作为参数
更简单的方法,等同调用伴生对象的apply
工厂方法
val numNames = Array("zero", "one", "two")//等价于Array.apply("zero", "one", "two")
链表 List
类型相同的不可变对象序列scala.List
// ::: 是连接两个链表 concatenation
val oneTwo = List(1, 2)
val threeFour = List(3, 4)
val oneTwoThreeFour = oneTwo ::: threeFour
//空链表用List() 或者 Nil 表示
val oneTwoThree = 1 :: 2 :: 3 :: Nil
运算符函数,通常是在左操作数上调用该方法,例如
a.*(b)
, 但是如果方法名以冒号结尾,则在右操作数上调用该方法,例如threeFour.:::(oneTwo)
元组 Tuple
类型可以不同的不可变对象容器
要实例化一个包含某些对象的新元组,只需将对象放在括号中,并用逗号分隔,之后可以用._N
(从1开始索引)访问
val pair = (99, "Luftballons")
println(pair._1)
println(pair._2)
Set/Map
集合库分为可变集合和不可变集合两种类型。 例如,数组总是可变的,列表总是不变的。 Scala还为Set/Map提供了可变和不可变的库,并且简单名称相同,完全限定名称不同,因为每个名称都位于不同的包中
var jetSet = Set("Boeing", "Airbus") //本质上调用apply方法,默认是immutable类型
jetSet += "Lear" //等同jetSet = jetSet + "Lear"
println(jetSet.contains("Cessna"))
如果使用mutable类型
import scala.collection.mutable
val movieSet = mutable.Set("Hitch", "Poltergeist")
movieSet += "Shrek" //调用方法 += : movieSet.+=("Shrek")
println(movieSet)
明确使用HashSet
import scala.collection.immutable.HashSet
val hashSet = HashSet("Tomatoes", "Chilies")
Map的情况:
import scala.collection.mutable
val treasureMap = mutable.Map[Int, String]()
treasureMap += (1 -> "Go to island.")
treasureMap += (2 -> "Find big X on ground.")
treasureMap += (3 -> "Dig.")
println(treasureMap(2))
Scala程序中的任何对象上调用
->
方法,返回一个包含键和值的双元素元组
默认immutable的情况
val romanNumeral = Map(1 -> "I", 2 -> "II", 3 -> "III", 4 -> "IV", 5 -> "V")
println(romanNumeral(4))