目录
1.2 Scala的基础语法
每种编程语言都有一套自己的语法规范,Scala语言也不例外,同样需要遵守一定的语法规范。
声明值和变量
1.2.1 Scala有两种类型的变量
- 使用关键字var声明的变量,值是可变的;
- 使用关键字val声明的变量,也叫常量,值是不可变的。
var myVar: String = "Hello" //使用关键字var声明的变量
val age: Int = 10 //使用关键字val声明的变量
有以下几个事项需要注意:
- Scala中的变量在声明时必须进行初始化。
- 使用var声明的变量可以在初始化后再次对变量进行赋值;
- 使用val声明的常量的值不可被再次赋值。
声明变量时,我们可以不给出变量的类型,因为在初始化的时候,Scala的类型推断机制能够根据变量的初始化的值自动推算出来。
上述声明变量myVar和age的代码,等同于下列代码:
var myVar = "Hello" //使用关键字var声明的变量
val age = 10 //使用关键字val声明的变量
- 使用关键字var或val声明变量时,后面紧跟的变量名称不能和Scala中的保留字重名,而且变量名可以以字母或下划线开头,且变量名是严格区分大小写的。
1.2.2 数据类型
任何一种编程语言都有特定的数据类型,Scala也不例外。与其他语言相比,Scala中的所有值都有一个类型,包括数值和函数。
Scala中数据类型的层次结构
从图1-11中可以看出,Any是所有类型的超类型,也称为顶级类型,它包含两个直接子类,具体如下:
- AnyVal:表示值类型,值类型描述的数据是一个不为空的值,而不是一个对象。它预定义了9种类型,分别是Double、Float、Long、Int、Short、Byte、Unit、Char和Boolean。其中,Unit是一种不代表任何意义的值类型,它的作用类似Java中void。
- AnyRef:表示引用类型。可以认为,除值以外,所有类型都继承自AnyRef。
在Scala数据类型层级结构底部,还有两个数据类型,分别是Nothing和Null,具体介绍如下:
- Nothing:所有类型的的子类型,也称为底部类型。它觉的用途是发出终止信号,例如抛出异常、程序退出或无限循环。
- Null:所有引用类型的子类型,它主要用途是与其他JVM语言互操作,几乎不在Scala代码中使用。
1.2.3 算术和操作符重载
Scala中算术操作符(+、-、*、/、%)的作用和Java是一样的,位操作符(&、|、>>、<<)也是一样的。特别强调的是,Scala的这些操作符其实是方法。例如,a+b其实是a.+(b)的简写。
Scala没有提供操作符++和--。如果我们想实现递增或者递减的效果,可以使用“+=1”或者“-=1”这种方式来实现。
1.2.4 控制结构语句
在Scala中,控制结构语句包括条件分支语句和循环语句
- 条件分支语句
//if语句的语法格式如下: if (布尔表达式1){ 语句块 } // if……else语句 if (布尔表达式1){ 语句块 } else { 语句块 } // if……else if……else语句 if (布尔表达式1){ 语句块 } else if(布尔表达式2){ 语句块 } else if(布尔表达式3){ 语句块 } else { 语句块 } // if……else嵌套语句 if (布尔表达式1){ 语句块 if(布尔表达式2){ 语句块 } }else if (布尔表达式3){ 语句块 else if (布尔表达式4){ 语句块 } }else{ 语句块 } |
示例代码如下:
- 循环语句
Scala中的for语句和Java中的循环语句在语法上有较大的区别,我们介绍一下Scala中的for循环语句。
for循环语句的语法如下:
for(变量<-表达式/数组/集合){ 循环语句; } |
下面,我们通过从0循环到9,每循环一次则就将该值打印输出进行操作演示。在Scala语法中,可以使用”0 to 9”表示从0到9的范围,范围包含9,示例代码如下:
Dos 下:
IDEA下:
//0 1 2 3 4 5 6 7 8 9
Scala在for循环语句中可以通过使用if判断语句过滤一些元素,多个过滤条件用分号分隔开。例如,输出0-9范围中大于5的偶数,示例代码如下:
Scala中的while循环语句和Java中的完全一样,语法格式如下:
while(布尔表达式){ 循环语句; } |
下面,我们通过打印输出奇数的案例来演示while的使用。假设有一个变量x=1,判断是否小于10,如果是则打印输出,然后再进行+2运算。示例代码如下:
do…while循环语句的语法格式如下:
do{ 循环语句; }while(布尔表达式) |
do…while循环语句与while语句的主要区别是,do…while语句的循环语句至少执行一次,示例代码如下:
1.2.5 方法和函数
在Scala中,它和Java一样也是拥有方法和函数。Scala的方法是类的一部分,而函数是一个对象可以赋值给一个变量。Scala中可以使用def语句和val语句定义函数,而定义方法只能使用def语句。下面分别对Scala的方法和函数进行讲解。
- 方法
Scala方法的定义格式如下:
def functionName ([参数列表]):[return type]={ function body return [expr] } |
下面定义一个方法add,实现两个数相加求和,示例代码下:
|
Scala的方法调用的格式如下:
|
下面,在类Test中,定义一个方法addInt,实现两个整数相加求和。在这里, 我们通过“类名.方法名(参数列表)”来进行调用,示例代码如下:
|
- 函数
Scala中的函数是一个对象,可以赋值给一个变量。
Scala函数的定义语法格式如下:
val functionName =([参数列表])=>function body |
下面,定义一个函数addInt,实现实现两个整数相加求和,示例代码如下:
|
- 方法转换成函数
方法转换成函数的格式如下:
val f1 = m _ |
在上述的格式中,方法名m后面紧跟一个空格和下划线,是为告知编译器将方法转换成函数,而不是要调用这个方法。下面,定义一个方法m,实现将方法m转成函数,示例代码如下:
|
小提示:
Scala方法的返回值类型可以不写,编译器可以自动推断出来,但是对于递归方法来说,必须要指定返回类型。
1.3 Scala的数据结构
在编写程序代码时,经常需要用到各种数据结构,选择合适的数据结构可以带来更高的运行或者存储效率,Scala提供了许多数据结构,例如常见的数组、元组和集合等。
1.3.1 数组
数组(Array)主要用来存储数据类型是每个人元素。
- 数组定义与使用
Scala中的数组分为定长数组和变长数组,这两种数组的定义方式如下:
New Array[T] (数组长度) //定义定长数组 ArrayBuffer[T]( ) //定义变长数组 |
注意:定义定长数组,需要使用new关键字,而定义变长数组时,则需要导包import scala.collection.mutable.ArrayBuffer。
下面,通过一个例子来演示Scala数组简单使用,具体代码如文件1-2所示。
Ch01_ArrayDemo.scala
package cn.itcast.scala import scala.collection.mutable.ArrayBuffer object Ch01_ArrayDemo { def main(args: Array[String]): Unit = { //定义定长数组:定义长度为8的定长数组,数组中的每个元素初始化为0 val arr1 = new Array[Int](8) //打印数组,内容是数组的hashcode值 println(arr1) //定义变长数组(数组缓冲),需要导入包:import scala.collection.mutable.ArrayBuffer val arr2 = ArrayBuffer[Int]() //向变长数组中追加元素 arr2 += 1 //打印变长数组 println(arr2) //向变长数组中追加多个元素 arr2 += (2,3,4,5) println(arr2) //追加一个定长数组 arr2 ++= Array(6,7) println(arr2) //追加一个变长数组(数组缓冲) arr2 ++= ArrayBuffer(8,9) println(arr2) //在变长数组的某个位置插入元素 arr2.insert(0,-1,0) println(arr2) //删除数组的某个元素 arr2.remove(0) println(arr2) } } |
- 数组的遍历
Scala中,如果想要获取数组中的每一个元素,则需要将数组进行遍历操作。
Ch02_ArrayTraversal.scala
package cn.itcast.scala object Ch02_ArrayTraversal { def main(args: Array[String]): Unit = { //定义定长数组 //val array = new Array[Int](8) //方式1 val myArr = Array(1.9, 2.9, 3.4, 3.5) //方式2 //打印输出数组中的所有元素 for(x<-myArr){ print(x+" ") } println() //计算数组中所有元素的和 var total = 0.0 for(i <- 0 to (myArr.length-1)){ total += myArr(i) } println("总和为:"+total) //查找数组中的最大值 var max = myArr(0) for(i <- 1 to (myArr.length-1)){ if(max < myArr(i)){ max = myArr(i) } } println("最大值为:"+max) } } |
- 数组转换
数组转换就是通过yield关键字将原始的数组进行转换,会产生一个新的数组,然而原始的数组保持不变。定义一个数组,实现将偶数取出乘以10后生成一个新的数组,具体代码如文件1-4所示。
Ch03_ArrayYieldTest.scala
package cn.itcast.scala object Ch03_ArrayYieldTest { def main(args: Array[String]): Unit = { //定义一个数组 var arr = Array(1,2,3,4,5,6,7,8,9) //将偶数取出乘以10后再生成一个新的数组 val newArr = for (e <- arr if e%2 == 0) yield e * 10 println(newArr.toBuffer) //将定长数组转为变长数组 } } |
1.3.2 元组
Scala的元组是对多个不同类型对象的一种简单封装,它将不同的值用小括号括起来,并用逗号作分隔,即表示元组。
- 创建元组
创建元组的语法格式如下:
val tuple=(元素,元素...) |
下面,通过简单的例子进行演示创建元组,例如:创建一个包含String类型、Double类型以及Int类型的元组,具体代码如下:
scala> val tuple = ("itcast",3.14,65535) tuple: (String, Double, Int) = (itcast,3.14,65535) |
- 获取元组中的值
在Scala中,获取元组中的值是通过下划线加脚标(例如:tuple._1,tuple._2)来获取的,元组中的元素脚标是从1开始的。
scala> tuple._1 # 获取第一个值 res0: String = itcast scala> tuple._2 # 获取第一个值 res1: Double = 3.14 |
- 拉链操作
在Scala的元组中,可以通过使用“zip”命令将多个值绑定在一起。例如,定义两个数组,分别是score和names,将这两个数组捆绑在一起,具体代码如下:
scala> val scores = Array(88,95,80) scores: Array[Int] = Array(88, 95, 80) scala> val names =Array("zhangsan","lisi","wangwu") names: Array[String] = Array(zhangsan, lisi, wangwu) scala> names.zip(scores) res2: Array[(String, Int)] = Array((zhangsan,88), (lisi,95), (wangwu,80)) |
注:当两个数组个数不等时,会自动适配较短长度,多余元素无相应匹配元素会被自动抛弃。
1.3.3 集合
在Scala中,集合有三大类: List、Set以及Map。
Scala 集合分为可变的(mutable)和不可变(immutable)的集合。其中,可变集合可以在适当的地方被更新或扩展,意味着可以对集合进行修改、添加、移除元素;不可变集合类,相比之下,初始化后就永远不会改变。
- List
在Scala中,List列表和数组类似,列表的所有元素都具有相同类型。这里的List默认是不可变列表,如果要定义可变列表,需要导入import scala.collection.mutable.ListBuffer包。
定义不同类型列表List,具体代码如下:
// 字符串 val fruit: List[String] =List("apples","oranges","pears") // 整型 val nums: List[Int] = List(1, 2, 3, 4) // 空 val empty: List[Nothing] = List() // 二维列表 val dim: List[List[Int]] = List( List(1, 0, 0), List(0, 1, 0), List(0, 0, 1) ) |
在Scala中,可以使用“Nil”和“::”操作符来定义列表。
// 字符串 val fruit = "apples":: ("oranges":: ("pears" :: Nil)) // 整型 val nums = 1 :: (2 :: (3 :: ( 4 :: Nil))) // 空列表 val empty = Nil // 二维列表 val dim = (1 :: (0 :: (0 :: Nil))) :: (0 :: (1 :: (0 :: Nil))) :: (0 :: (0 :: (1 :: Nil))) :: Nil |
Scala也提供了很多操作List的方法,如表1-1所示。
方法名称 |
相关说明 |
head |
返回列表第一个元素 |
tail |
返回一个列表,包含除了第一元素之外的其他元素 |
isEmpty |
在列表为空时返回true,否则返回false |
take |
获取列表前n个元素 |
contains |
判断是否包含指定元素 |
示例代码如下:
Ch04_ListTest.scala
package cn.itcast.scala object Ch04_ListTest { def main(args: Array[String]): Unit = { //定义List集合 //val fruit:List[String] = List("apples","oranges","pears") val fruit = "apples"::("oranges"::("pears"::Nil)) val nums = Nil println("Head of fruit:" + fruit.head) println("Tail of fruit:" + fruit.tail) println("check if fruit is empty:"+fruit.isEmpty) println("check if nums is empty:"+nums.isEmpty) println("Take of fruit:"+fruit.take(2)) println("contains of fruit oranages:"+fruit.contains("oranges")) } } |
- Set
在Scala中,Set是没有重复对象的集合,所有元素都是唯一的。默认情况下,Scala 使用不可变Set集合,若想使用可变的Set集合,则需要引入 scala.collection.mutable.Set 包。
定义Set集合的语法格式如下:
val set: Set[Int] = Set(1,2,3,4,5) |
Scala提供了很多操作Set集合的方法。接下来,我们列举一些操作Set集合的常见方法,具体如表1-2所示。
方法名称 |
相关说明 |
head |
返回Set集合的第一个元素 |
tail |
返回除第一个之外的所有元素组成的Set集合 |
isEmpty |
若Set集合为空,则返回true,否则返回false |
take |
获取Set集合前n个元素 |
contains |
判断Set集合是否包含指定元素 |
具体代码如文件1-6W所示。
Ch05_SetTest.scala
package cn.itcast.scala object Ch05_SetTest { def main(args: Array[String]): Unit = { //定义Set集合 val site = Set("Itcast","Google","Baidu") val nums:Set[Int] = Set() println("第一个网站是:"+site.head) println("最后一个网站是:"+site.tail) println("site集合是否为空:"+site.isEmpty) println("nums集合是否为空:"+nums.isEmpty) println("查看site集合的前两个网站:"+nums.take(2)) println("site集合中是不包含网站Google:"+site.contains("Google")) } } |
- Map
在Scala中,Map是一种可迭代的键值对(key/value)结构,并且键是唯一的,值不一定是唯一的,所有的值都是通过键来获取的。Map中所有元素的键与值都存在一种对应关系,这种关系即为映射。Map有两种类型,可变集合与不可变集合,默认是不可变Map。若需要使用可变的Map集合,则需要引入 import scala.collection.mutable.Map 类。
定义Map集合的语法格式如下:
var A:Map[Char,Int] = Map(键 -> 值,键 -> 值...) //Map键值对,键为Char,值为Int |
Scala也提供了很多操作Map集合的方法。接下来,我们列举一些操作Map集合的常见方法,具体如下所示。
方法名称 |
相关说明 |
() |
根据某个键查找对应的值,类似于Java中的get() |
contains() |
检查Map中是否包含某个指定的键 |
getOrElse() |
判断是否包含键,若包含返回对应值,否则返回其他的 |
keys |
返回Map所有的键(key) |
values |
返回Map所有的值(value) |
isEmpty |
若Map为空时,返回true |
示例如文件所示:
package cn.itcast.scala object Ch06_MapTest { def main(args: Array[String]): Unit = { //定义Map集合 val colors = Map("red"-> "#FF0000", "azure"-> "#F0FFFF", "peru"-> "#CD853F") val peruColor = if(colors.contains("peru")) colors("peru") else 0 val azureColor = colors.getOrElse("azure",0) println("获取colors中键为red的值:"+colors("red")) println("获取colors中所有的键:"+colors.keys) println("获取colors中所有的值:"+colors.values) println("检测colors是否为空:"+colors.isEmpty) println("判断colors中是否包含键peru,包含则返回对应的值,否则返回0:"+peruColor) println("判断colors中是否包含键azure,包含则返回对应的值,否则返回0:"+azureColor) } } |