一、声明值和变量
Scala中有两种类型的变量。
一种是val,是不可变的,在声明时就必须被初始化,而且初始化以后就不能再赋值;另一种是var,是可变的,声明的时候需要进行初始化,初始化以后还可以再次对其赋值。
Note:在项目的开发中建议使用val 也就是常量。避免数据被随意地更改。
val变量
scala> val myStr = "Hello World!"
myStr: String = Hello World!
Scala具有“类型推断”能力,可以自动推断出变量的类型。
当然,我们也可以显式声明变量的类型:
scala> val myStr2 : String = "Hello World!"
myStr2: String = Hello World!
需要说明的是,上面的String类型全称是java.lang.String,也就是说,Scala的字符串是由Java的String类来实现的,因此,我们也可以使用java.lang.String来声明,具体如下:
scala> val myStr3 : java.lang.String = "Hello World!"
myStr3: String = Hello World!
但是,为什么可以不用java.lang.String,而只需要使用String就可以声明变量呢?这是因为,在每个应用程序中,Scala都会自动添加一些引用,这样,就相当于在每个程序源文件的顶端都增加了一行下面的代码:
import java.lang._ //java.lang包里面所有的东西
因为myStr是val变量,因此,一旦初始化以后,就不能再次赋值,所以,下面我们执行的再次赋值操作会报错:
scala> myStr = "Hello Scala!"
<console>:8: error: reassignment to val
myStr = "Hello Scala!"
^
var变量
如果一些变量,需要在初始化以后还要不断修改它的值(比如商品价格),则需要声明为var变量。下面我们把myPrice声明为var变量,并且在声明的时候需要进行初始化:
scala> var myPrice : Double = 9.9
myPrice: Double = 9.9
然后,我们可以再次对myPrice进行赋值:
scala> myPrice = 10.6
myPrice: Double = 10.6
注意:
1)不管是val类型的变量还是var类型的变量 在声明的时候都要进行初始化,否则报错
2)var声明的变量可以使用占位符 “_”进行初始化;String 类型使用 "_"进行初始化时变量为null;Int 、Float、Double、等基本类型使用“_”被初始化为0;
Char 类型使用“_”被初始化为?
3)可以使用lazy关键字来修饰 val声明的变量 表示只有这个变量真正被使用的时候才去赋值。
二、基本数据类型和操作
Scala中共有九种基本类型的数据
Byte 8位、
Short 16位
Int 32位
Long 64位
Float 32位
Double 64位
Char
String
Boolean
Scala的基本数据类型和java的基本数据类型一 一对应 不同的是Java的基本数据类型首字母不需要大写,Scala的首字母必须大写,这是因为Scala中所有的值类型都是对象。
基本类型操作
Scala语言是纯面向对象编程语言,在Scala中一切皆对象,所有的操作都是方法的调用。
1)算数运算符操作
在Scala中,可以使用加(+)、减(-) 、乘(*) 、除(/) 、余数(%)等操作符,而且,与java不同的是这些操作符都是方法。例如,5 + 3和(5).+(3)是等价的,也就是说:
a 方法 b
a.方法(b)
上面这二者是等价的。前者是后者的简写形式,这里的+是方法名,是Int类中的一个方法。具体代码如下:
scala> val sum1 = 5 + 3
sum1: Int = 8
scala> val sum2 = (5).+(3)
sum2: Int = 8
需要注意的是,和Java不同,在Scala中并没有提供++和- -操作符,当需要递增和递减时,可以采用如下方式表达:
scala> var i = 5;
i: Int = 5
scala> i += 1
scala> println(i)
6
2)关系运算操作
大于(>)、小于(<)、大于等于(>=)和小于等于(<=),会产生Boolean类型的结果。
3)逻辑运算操作
&& 和 ||
4)位运算操作
位与(&) 、位或(|)、位异或(^)、取反(~)、左移位(<<)、右移位(>>)、无符号左移位(<<<)、无符号右移位(>>>)
//整型 3对应的二进制: 000000000 0000000000 00000000 00000011
//整型 5对应的二进制: 000000000 0000000000 00000000 00000101
//位与(&)操作后的二进制: 000000000 0000000000 00000000 00000001
scala>3 & 5
res25: Int = 1
//整型 3对应的二进制: 000000000 0000000000 00000000 00000011
//整型 5对应的二进制: 000000000 0000000000 00000000 00000101
//位或(|)操作后的二进制: 000000000 0000000000 00000000 00000111
scala>3 | 5
res26: Int = 7
//整型 3对应的二进制: 000000000 0000000000 00000000 00000011
//整型 5对应的二进制: 000000000 0000000000 00000000 00000101
//位异或(^)操作后的二进制: 000000000 0000000000 00000000 00000110
scala>3 ^ 5
res27: Int = 6
//整型 3对应的二进制: 000000000 0000000000 00000000 00000011
//取反操作后的二进制: 11111111 11111111 11111111 11111100
scala>~3
res28: Int = -4
//整型 6对应的二进制: 000000000 0000000000 00000000 00000110
//左移一位: 000000000 0000000000 00000000 00001100
scala>6<<1
res29: Int = 12
//整型 6对应的二进制: 000000000 0000000000 00000000 00000110
//右移一位: 000000000 0000000000 00000000 00000011
scala>6>>1
res30: Int = 3
//无符号右移: 11111111 11111111 11111111 11111111
//移动后的结果: 000000000 0000000000 00000000 00000001
scala>-1>>31
res31: Int = 1
5)对象比较运算操作
Scala中对象的比较和java中对象的比较不同,Scala是基于内容进行比较的,而java是比较的对象的引用,即:比较的是物理内存地址是否一样。
6)字符串运算操作
Scala中的String类型实际上就是java中的String的类型,因此可以调用java 中String类型的所有方法。
三、运算符优先级
四、元组类型
1)元组是Scala中特殊的类型,元组是不同类型值的聚集,它可以将不同类型的值放在一个变量中进行存储。
scala>var tuple=("hello","China",1)
tuple: (String, String, Int) = (hello,China,1)
2)访问元组的内容,通过 变量名._N的方式,其中N代表元组中元素的索引号,从1开始。
scala> tuple._1
res14: String = hello
3)在使用的时候还可以将元组的内容进行提取,对变量进行初始化。
scala> val (first,second,third)=tuple
first: String = hello
second: String = China
third: Int = 1
scala> println(first)
hello
4)对应元组使用== 进行比较的时候实际上比较的是元组中对应索引号的内容。
scala> var tuple=("hello","China",1)
tuple: (String, String, Int) = (hello,China,1)
scala> var tuple2=("hello","China",1)
tuple2: (String, String, Int) = (hello,China,1)
scala> tuple==tuple2
res16: Boolean = true
scala> var tuple3=("hello",1,"China")
tuple3: (String, Int, String) = (hello,1,China)
scala> tuple==tuple3
res17: Boolean = false
五、符号类型
1)Symbol是Scala中常用的一种符号类型,符号类型的定义需要使用 ’符号。
//使用 ’定义符号类型的变量,scala类型推断为Symbol类型
scala> val s='start
s: Symbol = 'start
//明确指定是符号类型
scala> val s1:Symbol= 'stop
s1: Symbol = 'stop
符号类型主要起标识的作用,在模式匹配、内容的判断中比较常用。
scala> if(s1=='start) println("start.....") else println("other...............")
other...............
2)符号类型的变量在输出的时候会按照原样输出
scala> println(s1)
'stop
3)与String类型、元组类型等变量一样,使用==符号进行变量比较,比较的是变量的内容而不是引用。
scala> val s2='start
s2: Symbol = 'start
scala> val s3='start
s3: Symbol = 'start
scala> s2==s3
res20: Boolean = true
偏函数
/*偏函数 * 1)概念 * Scala中的Partia Function是一个Trait,其的类型为PartialFunction[A,B],其中接收一个类型为A的参数,返回一个类型为B的结果。 * 偏函数之所以“偏”,原因在于它们并不处理所有可能的输入,而只处理那些能与至少一个case 语句匹配的输入。 * 2)在偏函数中只能使用case 语句,而整个函数必须用花括号{}包围 * 3)如果偏函数被调用,而函数的输入却与所有语句都不匹配,系统就会抛出一个MatchError运行时错误。 * 4)偏函数内部有一些方法,比如isDefinedAt、OrElse、 andThen、applyOrElse等。 * isDefinedAt:判断传入来的参数是否在这个偏函数所处理的范围内。 */ object PartialFunction { def main(args: Array[String]): Unit = { val pf1: PartialFunction[Int, String] = { case 1 => "One" case 2 => "Two" case 3 => "Three" case _ => "Other" } println(pf1(1)) //One println(pf1(2)) //Two println(pf1(4)) //Other val pf2: PartialFunction[Int, String] = { case 1 => "One" case 2 => "Two" case 3 => "Three" } // println(pf2(4)) //MatchError 錯誤 /*常用方法 * 1)isDefinedAt 判断传入的参数是否在这个偏函数处理的范围内 * 刚才定义的pf来尝试使用isDefinedAt(),只要是数字都是正确的,因为有case _=>"Other"这一句。 * 如果换成其他类型就会报错。*/ pf1.isDefinedAt(1) //true // pf1.isDefinedAt("2") pf2.isDefinedAt(4) //flase if (pf2.isDefinedAt(4)) { println(pf2(4)) } /*2)orElse : 将多个偏函数组合起来使用,效果类似case语句*/ val onePF: PartialFunction[Int, String] = { case 1 => "One" } val twoPF: PartialFunction[Int, String] = { case 2 => "Two" } val threePF: PartialFunction[Int, String] = { case 3 => "Three" } val otherPF: PartialFunction[Int, String] = { case _ => "Other" } // 将多个偏函数连接 val newPF = onePF orElse twoPF orElse threePF orElse otherPF newPF(3) /*3)andThen: 相当于方法的连续调用,比如g(f(x))。*/ val pf3: PartialFunction[Int, String] = { case i if i == 1 => "One" } val pf4: PartialFunction[String, String] = { case str if str == "One" => "The number is 1" } val num = pf3 andThen pf4 println(num(1)) //pf3的结果返回类型必须和pf4的参数传入类型必须一致,否则会报错。 /*4)applyOrElse:它接收2个参数,第一个是调用的参数,第二个是个回调函数。如果第一个调用的参数匹配,返回匹配的值,否则调用回调函数。*/ onePF.applyOrElse(1, { num: Int => "two" }) onePF.applyOrElse(2, { num: Int => "two" }) /*在这个例子中,第一次onePF匹配了1成功则返回的是"One"字符串。第二次onePF匹配2失败则触发回调函数,返回的是"Two"字符串。*/ } }