Scala基础(一)部署、数据类型及简单语法
概述
官网:
Scala是运行在 JVM 上的多范式编程语言,同时支持面向对象编程(OOP)和函数式编程(FP)。
官网文档可以看到已经有Scala3,但还是要用Scala2(老版本稳定性好):
Scala优点:语法简洁、灵活。是静态编程语言(源码→编译[确定数据类型,避免某些bug]→执行,比起Python这种动态编程语言直接 源码→加载执行 安全)。
部署
安装路径不能有中文和空格!!!
Win10部署Scala SDK
先安装JDK1.8,配置环境变量。之前配置过就可以略过。
解压到某个文件夹,安装路最好不要有中文和空格!!!之后win+Q搜索环境变量,即可配置环境变量:
SCALA_HOME=C:\soft\scala-2.11.12
path=%SCALA_HOME%\bin;
win+R,输入cmd
回车,敲scala
(启动Scala解释器)验证是否成功:
敲:quit
(这个:必须有)可以退出cmd模式的scala。
Linux部署Scala SDK
上传、解压、配置环境变量、shell敲scala验证,流程与Win10部署差不多。
cd /export/software/
rz
tar -zxvf scala-2.11.12.tgz -C /export/server
cd /export/server/
scp -r scala-2.11.12 node2:$PWD
scp -r scala-2.11.12 node3:$PWD
vim /etc/profile
末尾插入:
#SCALA_HOME
export SCALA_HOME=/export/server/scala-2.11.12
export PATH=$PATH:$SCALA_HOME/bin
保存后:
source /etc/profile
敲scala测试是否成功:
[root@node1 server]# scala
Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_241).
Type in expressions for evaluation. Or try :help.
scala> print("hello scala")
hello scala
scala> :quit
再配置node2和node3的环境变量并测试,不再赘述。
IDEA部署Scala插件
当然不可能一直用cmd来做Scala,idea更方便些。。。插件中搜索Scala,自动安装的插件和本机兼容性好。
选Plugins,搜索scala:
当然安装下载最多的。。。安装完成后点Restart IDE或者手动关闭重启都可以:
重启后新建个项目:
简单使用,选Scala空白项目,后期可以使用Maven实现Scala与Java联合编程。
首次启动没有Scala的SDK,需要点Create:
如果搜不到,说明环境变量还没有刷新,需要重启计算机才行。中间随便点一下(变蓝)后OK即可点Finish。
在src中右键→New→Scala Class,就可以创建新的Scala类。当然为了不影响主体,也可以新建module方便测试:
选Object后会发生这种事。。。Scala严禁随意使用空格:
使用psvm
当然是不行的,要使用main
:
object HelloWorld {
def main(args: Array[String]): Unit = {
print("Hello World")
}
}
首次ctrl+shift+f10运行会很慢:
Hello World
Process finished with exit code 0
编译后发现编译出了.class
字节码文件:
反编译试试:
不明觉厉,但是可以看出这个class后缀的文件和正常的Java文件差不多,说明Scala是使用JVM的。
语法基础
Scala解释器
学习Scala基本语法可以考虑使用Scala解释器,不需要多余内容,可以像Linux命令一样,一次执行一条代码,马上可以看到结果。比起用idea写类更方便。
定义变量
Scala和Java的语法不太一样。标准套路:
val/var 变量名:变量类型 = 初始值
val定义的是不可重新赋值的变量,var定义的是可以重新赋值的变量。变量名在前,变量类型在后(变量类型可以省略,Scala可以自动推测),末尾不需要;(+;也不会报错,但是没什么用)。
//定义val,自动推测数据类型,数据的值不可修改
scala> val str0001="haha1"
str0001: String = haha1
scala> str0001="haha2"
<console>:12: error: reassignment to val
str0001="haha2"
//定义var,自动推测数据类型,数据的值可以修改
scala> var str0002="hehe1"
str0002: String = hehe1
scala> str0002="hehe2"
str0002: String = hehe2
//区分大小写
scala> val str0003:String = "0003"
str0003: String = 0003
scala> val str0003:string = "0003"
<console>:11: error: not found: type string
val str0003:string = "0003"
//没有""双引号包裹值会报错
当某些变量的数据量比较大,且不需要马上加载到JVM内存,就需要惰性赋值,需要的时候才加载到JVM内存。套路:
lazy val 变量名 = 表达式
//惰性赋值只能使用val,不能用var
scala> lazy var SQL1 = "select"
<console>:1: error: lazy not allowed here. Only vals can be lazy
lazy var SQL1 = "select"
//惰性赋值的val可以更改值
scala> val SQL1 = "select"
SQL1: String = select
scala> val SQL1 = "select1"
SQL1: String = select1
scala> SQL1
res1: String = select1
//使用"""三引号修饰字符串,可以换行输入
scala> lazy val SQL2="""
| SELECT
| *
| FROM
| table1;
| """
SQL2: String = <lazy>
scala> SQL2
res4: String =
"
SELECT
*
FROM
table1;
"
Scala中也有类似C#中使用$
拼接字符串的方式,但是毕竟不是同一种语言,插值表达式的套路有所不同:
scala> val name = "张三" //支持中文字符串
name: String = 张三
scala> val age = 20
age: Int = 20
scala> val personinfo = s"name = ${name},age = ${age}" //插值表达式
personinfo: String = name = 张三,age = 20
scala> println(personinfo) //输出变量
name = 张三,age = 20
scala> println(s"${personinfo}>>${1+2}"+"haha") //{}花括号内可以是运算式、对象.方法调用,还可以使用+连接字符串
name = 张三,age = 20>>3haha
数据类型
由于需要使用JVM,基本数据类型与Java的包装类数据类型基本一致。
基础类型 | 类型说明 |
---|---|
Byte | 8位有符号整数 |
Short | 16位有符号整数 |
Int | 32位有符号整数 |
Long | 64位有符号整数 |
Char | 16位无符号Unicode字符 |
String | Char类型的序列(字符串) |
Float | 32位单浮点数 |
Double | 64位双浮点数 |
Boolean | 布尔,true或者false |
Scala所有数据类型都是大写字母开头。一般让Scala自动推测数据类型就好。
类型 | 说明 |
---|---|
Any | 所有类型的父类 |
AnyVal | 所有数值类型的父类 |
AnyRef | 所有对象类型(引用数据类型)的父类 |
Unit | 表示无值(void),用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成() |
Null | null或者空引用 |
Nothing | 所有类型的子类(抛出的一次返回值是Nothing) |
运算符
类别 | 操作符 |
---|---|
算数运算符 | +、-、*、/ |
关系运算符 | >、<、==、!=、>=、<= |
逻辑运算符 | &&、||、! |
位运算符 | &、||、^、<<、>> |
Scala中没有++
与--
运算符:
scala> 5
res14: Int = 5
scala> 5++
<console>:12: error: value ++ is not a member of Int
5++
^
scala> 5--
<console>:12: error: value -- is not a member of Int
5--
Scala使用==
与!=
比较字符串的值是否一致,使用eq
方法比较2个对象的引用值:
scala> val str1 = "aaa"
str1: String = aaa
scala> val str2 = str1+""
str2: String = aaa
scala> str1 == str2
res12: Boolean = true //字符串内容相同
scala> str1.eq(str2)
res13: Boolean = false //字符串的引用不同
块表达式
Scala也是使用{}
花括号来表示一个代码块(代表这一大坨是一个整体)。块表达式有值:
scala> val a={
| 1+1
| 3
| 5
| }
<console>:12: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
1+1
^
<console>:13: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
3
^
a: Int = 5
显然块表达式的值就是最后一个表达式的值。如果只有一个表达式,显然{}
可以省略。
条件表达式
对应其它语言的if判断的分支结构。Scala有if/else
,但是没有三元表达式
(可以自己定义方法用if/else实现)。也有类似Java和C#中Switch/Case
的功能。
scala> val a=20
a: Int = 20
scala> val b = if(a!=20) 5 else 10 //实现if/else
b: Int = 10
scala> var c = a match { //需要使用match实现switch/case
| case 10 => 10
| case 20 => 21
| case 30 => 32
| case _ => 0
| }
c: Int = 21
if/else可以嵌套多层,也可以多分支,不赘述。
循环表达式
while
循环和java相同:
scala> var a = 5
a: Int = 5
scala> while(a>=0) {a=a-1;print(a)} //使用;分割同一行的语句
43210-1
当然也可以使用while(true)的死循环。。。
for
循环的套路则有所不同:
scala> val array1 = Array(11,22,33)
array1: Array[Int] = Array(11, 22, 33)
scala> for( i <- array1) println(i) //可以遍历数组/集合/表达式
11
22
33
scala> for(i <- 1 to 5) print(i) //to是包含后边的参数
12345
scala> for(i <- 1 until 5) print(i) //until是不包含后边的参数
1234
scala> for(i <- 1 to 5 if i%2 != 0) print(i) //守卫条件
135
scala> val b = for( i <- array1) yield i*10+1 //for推导式
b: Array[Int] = Array(111, 221, 331)
scala> array1.map(_*10+1) //函数式编程更高效
res24: Array[Int] = Array(111, 221, 331)
可以直接遍历数组/集合/表达式
,还可以使用守卫条件
和for推导式
,比Java的for循环强大。
Scala没有Break
与Continue
关键字,好在提供了Breaks
类,可以模拟出相同的效果:
import scala.util.control.Breaks._
object BreakDemo {
def main(args: Array[String]): Unit = {
//模拟break
breakable{
for (i <- 1 to 10){
if(i>6) break()
else print(i)
}
}
println("*****-----华丽的分割线-----*****")
//模拟continue
breakable{
for (i <- 1 to 100){
if(i%10==0) break()
else print(i)
}
}
}
}
使用idea比较方便,当然cmd里也可以导包。。。
方法与函数
Java类中封装的一大坨功能模块叫方法(method直译),C和Lua中封装的功能模块叫函数(function直译),貌似区分并不明确。但是Scala中方法和函数有极大的区别。在Scala这种函数式编程语言中,函数是头等公民
(极其重要)。
方法
方法定义是这种套路:
def 方法名(变量名1:变量类型=默认值1,变量名2:变量类型=默认值2):返回类型 ={
//方法体
}
可以省略很多内容:
scala> def method1(a:Int,b:Int)=a+b //双参数方法
method1: (a: Int, b: Int)Int
scala> method1(1,2)
res3: Int = 3
scala> def method2=print("haha") //无参方法
method2: Unit
scala> method2
haha
scala> def method3(a:Int)(b:Int)=a+b //另一种格式的双参数方法
method3: (a: Int)(b: Int)Int
scala> method3(1)(2)
res34: Int = 3
但是递归方法(例如:求阶乘)不能省略:
scala> def method1(a:Int) = if(a<1) 1 else method1(a-1)*a
<console>:13: error: recursive method method1 needs result type
def method1(a:Int) = if(a<1) 1 else method1(a-1)*a
^
scala> def method1(a:Int):Int = if(a<1) 1 else method1(a-1)*a
method1: (a: Int)Int
scala> method1(5)
res6: Int = 120
调用无默认值的方法时不给参数会报错:
scala> def method1(a:Int) = if(a<1) 1 else method1(a-1)*a
scala> method1()
<console>:13: error: not enough arguments for method method1: (a: Int)Int.
Unspecified value parameter a.
method1()
scala> def method1(a:Int=5):Int = if(a<1) 1 else method1(a-1)*a //给定默认参数
method1: (a: Int)Int
scala> method1() //不给参数时调用默认参数
res11: Int = 120
带名参数的调用和C语言差不多。
Scala支持变长参数:
def 方法名(参数名1:参数类型*):返回类型={
//方法体
}
事实上可以省略很多内容:
scala> def method1(a:Int*)=a.sum
method1: (a: Int*)Int
scala> def method1(a:Int*)=a.sum
method1: (a: Int*)Int
scala> val array1 = Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)
array1: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23)
scala> method1(array1)
<console>:14: error: type mismatch; //数组与可变参数不匹配
found : Array[Int]
required: Int
method1(array1)
scala> method1(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)
res14: Int = 276
scala> method1(5)
res1: Int = 5
scala> method1{5} //只有1个参数时可以使用{}花括号调用
res2: Int = 5
scala> method1{1,5} //不止1个参数时不可以使用{}花括号调用
<console>:1: error: ';' expected but ',' found.
method1{1,5}
方法调用
OOP中常用的就是对象.方法(参数),这种是后缀调用
。但是Scala还可以使用对象 方法 参数,这种是中缀调用
:
scala> var a:Int=1
a: Int = 1
scala> a.to(10) //后缀调用
res15: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> a to (10) //中缀调用
res16: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
方法的操作符
scala> val str1 = "haha"
str1: String = haha
scala> val str2 = "hehe"
str2: String = hehe
scala> str1+str2
res40: String = hahahehe
scala> str1 +:str2
res37: scala.collection.immutable.IndexedSeq[Any] = Vector(haha, h, e, h, e)
scala> str1 :+str2
res39: scala.collection.immutable.IndexedSeq[Any] = Vector(h, a, h, a, hehe)
函数
函数的本质都是对象,都是FunctionN
的实例(N是函数传入参数的个数)。
scala> new function //要按Tab才会显示,默认最多22个参数
Function10 Function14 Function18 Function21 Function5 Function9
Function Function11 Function15 Function19 Function22 Function6 FunctionalInterface
Function0 Function12 Function16 Function2 Function3 Function7 PartialFunction
Function1 Function13 Function17 Function20 Function4 Function8
scala> def method1(a:Int,b:Int)=a+b //有def的是方法
method1: (a: Int, b: Int)Int //显示这是个方法
scala> method1(1,2)
res3: Int = 3
scala> val function1 = (a:Int,b:Int)=>a+b //无def是函数
function1: (Int, Int) => Int = <function2> //显示这是2个参数的函数
scala> function1(1,2)
res0: Int = 3
scala> def method2(p:(Int,Int)=>Int)
| =p(1,2)
method2: (p: (Int, Int) => Int)Int
scala> method2(function1) //function1是函数,作为参数传给method2
res2: Int = 3
scala> val function2 = (x:Int) =>x +3
function2: Int => Int = <function1>
scala> method2(function2) //类型不同,不能作为参数传递
<console>:14: error: type mismatch;
found : Int => Int
required: (Int, Int) => Int
method2(function2)
scala> val array1 = Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)
array1: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23)
scala> array1.map(function2)
res4: Array[Int] = Array(4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26)
scala> array1.map((x:Int) =>x*5) //使用匿名函数调用,省去了函数命名的过程
res5: Array[Int] = Array(5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115)
scala> array1.map(_*5) //使用_一步升天
res6: Array[Int] = Array(5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115)
函数可以作为变量传给方法,方法能够转换成函数(函数不能转换为方法):
scala> def method1(p:(Int,Int)=>Int)=p(1,2)
method1: (p: (Int, Int) => Int)Int
scala> def method2(x:Int,y:Int)=x+y
method2: (x: Int, y: Int)Int
scala> method2_ //方法需要空格隔开再+_才能转换成功
<console>:12: error: not found: value method2_
method2_
scala> method2 _ //方法 _:方法→函数
res9: (Int, Int) => Int = <function2>
scala> method1(method2 _) //转换后的函数作为参数传递给方法(显式转换)
res10: Int = 3
scala> method1(method2) //转换后的函数作为参数传递给方法(隐式转换)
res11: Int = 3
数组
Scala中,数组分为
- 定长数组Array(数组长度不可变,元素可变)
- 变长数组ArrayBuffer(数组长度可变,元素可变)
定长数组Array
scala> val array1 = new Array[Int](4) //没有初始值时需要new
array1: Array[Int] = Array(0, 0, 0, 0)
scala> array1
res0: Array[Int] = Array(0, 0, 0, 0)
scala> array1[0] //Scala中不是通过[]访问
<console>:1: error: identifier expected but integer literal found.
array1[0]
^
scala> array[1] //Scala中不是通过[]访问
<console>:1: error: identifier expected but integer literal found.
array[1]
scala> array1(0) //Scala中通过()访问
res2: Int = 0
scala> array1(0)=11
scala> array1
res4: Array[Int] = Array(11, 0, 0, 0)
scala> val array2 = Array(1,2,3) //有初始值时不需要new
array2: Array[Int] = Array(1, 2, 3)
变长数组ArrayBuffer
scala> :quit //先退出重开命令行
C:\Users\killer>scala
Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_241).
Type in expressions for evaluation. Or try :help.
scala> val AB1 = new ArrayBuffer[String]() //不导包会报错
<console>:11: error: not found: type ArrayBuffer
val AB1 = new ArrayBuffer[String]()
scala> import scala.collection.mutable.ArrayBuffer //变长数组使用前需要导包
import scala.collection.mutable.ArrayBuffer
scala> val AB1 = new ArrayBuffer[String]() //没有初值需要new
AB1: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer()
scala> val AB2 = ArrayBuffer("haha","hehe") //有初值不需要new
AB2: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(haha, hehe)
scala> AB2(1) //也是通过()访问,不是[]访问
res0: String = hehe
scala> AB2 += "a1" //+=是追加内容
res1: AB2.type = ArrayBuffer(haha, hehe, a1)
scala> AB2 + "a2" //+会变成字符串
res2: String = ArrayBuffer(haha, hehe, a1)a2
scala> AB2.append("a2") //append和+=都是末尾追加
scala> AB2
res4: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(haha, hehe, a1, a2)
scala> AB2 +="a1" //可重复添加相同内容
res6: AB2.type = ArrayBuffer(haha, hehe, a1, a2, a1)
scala> AB2 +="a2"
res7: AB2.type = ArrayBuffer(haha, hehe, a1, a2, a1, a2)
scala> AB2 -="a1" //-=只会去除第一个该内容的元素
res8: AB2.type = ArrayBuffer(haha, hehe, a2, a1, a2)
scala> AB2.remove("a2") //不能按内容移除
<console>:14: error: type mismatch;
found : String("a2")
required: Int
AB2.remove("a2")
^
scala> AB2.remove(4) //可以按照脚标移除
res10: String = a2
scala> AB2 //直接遍历
res11: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(haha, hehe, a2, a1)
scala> for(i <- AB2 ) println(i) //for直接遍历
haha
hehe
a2
a1
scala> AB2 ++= Array("hive", "sqoop") //使用++=来追加数组的内容
res13: AB2.type = ArrayBuffer(haha, hehe, a2, a1, hive, sqoop)
scala> for (i <- 0 to AB2.length-1) print(AB2(i)+" ") //for使用角标遍历
haha hehe a2 a1 hive sqoop
scala> for (i <- 0 to AB2.length) print(AB2(i)+" ") //也会越界
haha hehe a2 a1 hive sqoop java.lang.IndexOutOfBoundsException: 6
at scala.collection.mutable.ResizableArray$class.apply(ResizableArray.scala:43)
at scala.collection.mutable.ArrayBuffer.apply(ArrayBuffer.scala:48)
at $anonfun$1.apply$mcVI$sp(<console>:14)
at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:160)
... 32 elided
scala> for (i <- 0 until AB2.length) print(AB2(i)+" ") //for使用脚标遍历
haha hehe a2 a1 hive sqoop
数组常用算法
自带了多种算法,例如:升序排序sorted
、反转数组reverse
、累加sum
、最大值max
、最小值min
。
scala> AB2.sorted //String类型的可变长数组也可以排序
res18: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(a1, a2, haha, hehe, hive, sqoop)
scala> AB2.sorted.reverse //反转数组,链式编程
res19: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(sqoop, hive, hehe, haha, a2, a1)
scala> val array1 = Array(1,2,3,4,5,6)
array1: Array[Int] = Array(1, 2, 3, 4, 5, 6)
scala> array1.sum //累加
res25: Int = 21
scala> array1.max //求最大值
res26: Int = 6
scala> array1.min //求最小值
res27: Int = 1
scala> array1.reverse //反转数组
res29: Array[Int] = Array(6, 5, 4, 3, 2, 1)
scala> array1.reverse.sorted //升序排序,链式编程
res30: Array[Int] = Array(1, 2, 3, 4, 5, 6)
迭代访问数组
Scala为多种集合预置了迭代器iterator
,用于迭代访问集合。以数组为例:
scala> :quit
C:\Users\killer>scala //重启Scala命令行
Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_241).
Type in expressions for evaluation. Or try :help.
scala> val array1 = Array(11,12,13)
array1: Array[Int] = Array(11, 12, 13)
scala> val i1 = array1.iterator //为数组构建迭代器对象
i1: Iterator[Int] = non-empty iterator
scala> while(i1.hasNext) {println(i1);println(i1.next)} //迭代数组
non-empty iterator //迭代过程中不断指向下一个,迭代器非空
11
non-empty iterator
12
non-empty iterator
13
scala> i1 //迭代结束后迭代器清空
res2: Iterator[Int] = empty iterator
scala> i1.next //迭代器没有下一个元素时强行读取下一个会报错(指针越界)
java.util.NoSuchElementException: next on empty iterator
at scala.collection.Iterator$$anon$2.next(Iterator.scala:39)
at scala.collection.Iterator$$anon$2.next(Iterator.scala:37)
at scala.collection.IndexedSeqLike$Elements.next(IndexedSeqLike.scala:63)
... 32 elided
元组
使用()把不同数据类型的数据聚集起来就是元组,类似C语言的结构体
。当然元组中也可以有相同数据类型的数据。。。Scala内置了22个Tuple对象:
scala> :quit
C:\Users\killer>scala
Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_241).
Type in expressions for evaluation. Or try :help.
scala> new Tuple //要按Tab键才会出现
Tuple1 Tuple11 Tuple13 Tuple15 Tuple17 Tuple19 Tuple20 Tuple22 Tuple4 Tuple6 Tuple8
Tuple10 Tuple12 Tuple14 Tuple16 Tuple18 Tuple2 Tuple21 Tuple3 Tuple5 Tuple7 Tuple9
只有2个元素的就是对偶元组:
scala> val tuple1 = (11,"haha") //新建对偶元组
tuple1: (Int, String) = (11,haha)
scala> tuple1.swap //交换对偶元组的2个元素
res2: (String, Int) = (haha,11)
scala> tuple1 //swap交换不改变原先对偶元组的内容
res3: (Int, String) = (11,haha)
一般使用的不是对偶元组:
scala> val tuple2 = (1,1.2,true,"haha") //给定初始值创建
tuple2: (Int, Double, Boolean, String) = (1,1.2,true,haha)
scala> val tuple3 = new Tuple4(2,2.2,false,"hehe") //使用new创建
tuple3: (Int, Double, Boolean, String) = (2,2.2,false,hehe)
scala> tuple2._2 //使用._数字(从1开始)的方式访问
res9: Double = 1.2
scala> for(i <- tuple2) //不能使用for遍历元组
| print(i)
<console>:13: error: value foreach is not a member of (Int, Double, Boolean, String)
for(i <- tuple2)
scala> tuple2.productIterator.foreach(println) //可以使用Tab补全。需要变成迭代器才能遍历
1
1.2
true
haha
列表
可重复列表List
分为不可变的List与可变的ListBuffer。
scala> val list1=List(11,22,33,44,55) //不导包默认为不可变的List
list1: List[Int] = List(11, 22, 33, 44, 55)
scala> import scala.collection.mutable.ListBuffer //导包
import scala.collection.mutable.ListBuffer
scala> val list2=ListBuffer(66,77,88,99) //导包后可以用可变的ListBuffer
list2: scala.collection.mutable.ListBuffer[Int] = ListBuffer(66, 77, 88, 99)
scala> val list3 = 11::22::33 //使用::追加的方式构建列表,这种情况会报错(∵不能自动推测类型)
<console>:12: error: value :: is not a member of Int
val list3 = 11::22::33
scala> val list3 = 11::22::33::Nil //使用::追加的方式构建列表,末尾必须是Nil
list3: List[Int] = List(11, 22, 33)
scala> val list4=Nil //构建空的List
list4: scala.collection.immutable.Nil.type = List()
scala> list1.head //查看首个元素
res0: Int = 11
scala> list1.tail //查看去头元素(除首个元素外的其余元素)
res1: List[Int] = List(22, 33, 44, 55)
scala> list1 :+101 //可以:+在末尾追加元素
res9: List[Int] = List(11, 22, 33, 44, 55, 101)
scala> list1 //上述操作不影响原list
res10: List[Int] = List(11, 22, 33, 44, 55)
scala> list1(0) //按脚标获取数据(从0开始)
res27: Int = 11
scala> list1(0)=1 //不能修改不可变List的元素
<console>:14: error: value update is not a member of List[Int]
list1(0)=1
scala> list1 +=101 //表达式不转换为赋值,因为接收方不可赋值。
<console>:14: error: value += is not a member of List[Int]
Expression does not convert to assignment because receiver is not assignable.
list1 +=101
scala> list1.:+(101) //使用.:+后缀调用的方式追加元素
res16: List[Int] = List(11, 22, 33, 44, 55, 101)
scala> list1 //不影响原List
res17: List[Int] = List(11, 22, 33, 44, 55)
scala> list1 +:102 //前方追加元素不能识别数据类型
<console>:14: error: value +: is not a member of Int
list1 +:102
^
scala> list1.+:102 //使用.+:后缀调用的方式也不能识别数据类型
<console>:1: error: ';' expected but integer literal found.
list1.+:102
^
scala> list1.+:(102) //数据()小括号括起来就可以识别数据类型
res19: List[Int] = List(102, 11, 22, 33, 44, 55)
scala> list1.::(102) //::和+:同样是在头部追加元素
res21: List[Int] = List(102, 11, 22, 33, 44, 55)
scala> list2(0)=61 //可变列表ListBuffer可以通过脚标修改元素
scala> list2
res32: scala.collection.mutable.ListBuffer[Int] = ListBuffer(61, 77, 88, 99)
scala> list2+=101 //可变列表可以直接追加并覆盖原列表
res35: list2.type = ListBuffer(61, 77, 88, 99, 101)
scala> list2 +=(102) //尾部追加时没有()也可以识别
res36: list2.type = ListBuffer(61, 77, 88, 99, 101, 102)
scala> list2 +=101 //列表可以有重复的元素
res37: list2.type = ListBuffer(61, 77, 88, 99, 101, 102, 101)
scala> list2 -=101 //使用-只会移除首个该内容的元素
res38: list2.type = ListBuffer(61, 77, 88, 99, 102, 101)
scala> list3.to //使用Tab补全,可以查看更多方法
to toBuffer toIterable toList toParArray toSet toString toVector
toArray toIndexedSeq toIterator toMap toSeq toStream toTraversable
scala> list3.toArray //可以转换为Array数组
res39: Array[Int] = Array(11, 22, 33)
scala> list3.toList //可以转换为不可变列表List(没什么用。。。自己本身就是List)
res41: List[Int] = List(11, 22, 33)
scala> list2.to //可变与不可变列表的转换方法相同
to toBuffer toIterable toList toParArray toSet toString toVector
toArray toIndexedSeq toIterator toMap toSeq toStream toTraversable
还有很多方法,例如:压平、∩、∪。。。用的时候慢慢查。。。或者参照API。
不可重复列表Set
Set是无序不可重复的列表,主要用于去重,但是又会导致数据无序。。。同样是有可变Set与不可变Set:
scala> :quit //重启scala命令行
C:\Users\killer>scala
Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_241).
Type in expressions for evaluation. Or try :help.
scala> val set1 = Set(1,3,2,1,3,4,3,2,1,5) //自动去重
set1: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)
scala> import scala.collection.mutable.Set
import scala.collection.mutable.Set
scala> val set2 = Set(1,3,2,1,3,4,3,2,1,5) //自动去重
set2: scala.collection.mutable.Set[Int] = Set(1, 5, 2, 3, 4)
scala> set1+=6 //不可变Set不能修改元素
<console>:14: error: value += is not a member of scala.collection.immutable.Set[Int]
Expression does not convert to assignment because receiver is not assignable.
set1+=6
^
scala> set2 +=6 //可变Set可以修改元素
res2: set2.type = Set(1, 5, 2, 6, 3, 4)
scala> set2 -=6
res3: set2.type = Set(1, 5, 2, 3, 4)
映射Map
Scala中Map分为可变Map与不可变Map(长度不可改变,元素也不可改变)。和其它类型不同,可变与不可变都叫map,一字不差。。。想区分只能看有木有导包(不导包默认是不可变map,导包后可以使用可变map)。
定义Map按照这种套路:
val/var map = Map(键->值, 键->值, 键->值...) //键→值的键值对可读性更好
val/var map = Map((键, 值), (键, 值), (键, 值), (键, 值)...)
用起来还是比较简单的:
scala> :quit
C:\Users\killer>scala //重启scala命令行
Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_241).
Type in expressions for evaluation. Or try :help.
scala> val map1 = Map("name" -> "张三","age"->"13") //导包前为不可变Map
map1: scala.collection.immutable.Map[String,String] = Map(name -> 张三, age -> 13)
scala> val map2 = Map(("name","张三"),("age",23))
map2: scala.collection.immutable.Map[String,Any] = Map(name -> 张三, age -> 23)
scala> import scala.collection.mutable.Map //导包
import scala.collection.mutable.Map
scala> val map3 = Map("name" -> "张三","age"->"33") //导包后变为可变Map
map3: scala.collection.mutable.Map[String,String] = Map(age -> 33, name -> 张三)
scala> val map4 = Map(("name","张三"),("age",43))
map4: scala.collection.mutable.Map[String,Any] = Map(age -> 43, name -> 张三)
scala> map1 //可以直接看到键值对
res4: scala.collection.immutable.Map[String,String] = Map(name -> 张三, age -> 13)
scala> map1("name") //可以根据键查看值
res5: String = 张三
scala> map1("name")="lisi" //不能修改不可变Map的数据
<console>:14: error: value update is not a member of scala.collection.immutable.Map[String,String]
map1("name")="lisi"
^
scala> map1 +=("name"->"lisi") //不能修改不可变Map的数据
<console>:14: error: value += is not a member of scala.collection.immutable.Map[String,String]
Expression does not convert to assignment because receiver is not assignable.
map1 +=("name"->"lisi")
scala> map3("name")="lisi" //可以修改可变Map的数据
scala> map3
res7: scala.collection.mutable.Map[String,String] = Map(age -> 33, name -> lisi)
scala> map1("nama") //会报错
java.util.NoSuchElementException: key not found: nama
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:59)
at scala.collection.MapLike$class.apply(MapLike.scala:141)
at scala.collection.AbstractMap.apply(Map.scala:59)
... 32 elided
scala> map1.get("nama") //key不存在也不报错
res10: Option[String] = None
scala> map1.get("name") //相对安全。返回Option类型
res8: Option[String] = Some(张三)
scala> map3 +=("university"->"上兰村帝国技校") //可追加键值对
res11: map3.type = Map(age -> 33, name -> lisi, university -> 上兰村帝国技校)
scala> map3
res12: scala.collection.mutable.Map[String,String] = Map(age -> 33, name -> lisi, university -> 上兰村帝国技校)
scala> map3 +=(("k1","v1"),("k2","v2")) //可追加键值对
res13: map3.type = Map(k2 -> v2, k1 -> v1, age -> 33, name -> lisi, university -> 上兰村帝国技校)
scala> map3
res14: scala.collection.mutable.Map[String,String] = Map(k2 -> v2, k1 -> v1, age -> 33, name -> lisi, university -> 上兰村帝国技校)
scala> map3 +=(("k3","v3"),("k4","v4"),("k5","v5")) //说明键值对无序排列
res15: map3.type = Map(k2 -> v2, k5 -> v5, k4 -> v4, k1 -> v1, age -> 33, name -> lisi, k3 -> v3, university -> 上兰村帝国技校)
scala> map3
res16: scala.collection.mutable.Map[String,String] = Map(k2 -> v2, k5 -> v5, k4 -> v4, k1 -> v1, age -> 33, name -> lisi, k3 -> v3, university -> 上兰村帝国技校)
scala> for(i<- map3) println(i+";") //遍历Map
(k2,v2);
(k5,v5);
(k4,v4);
(k1,v1);
(age,33);
(name,lisi);
(k3,v3);
(university,上兰村帝国技校);
scala> map3.keys //返回Map中所有key并返回个set集合
res18: Iterable[String] = Set(k2, k5, k4, k1, age, name, k3, university)
scala> for(k <- map3.keys) println(s"${k}:${map3(k)}")
k2:v2
k5:v5
k4:v4
k1:v1
age:33
name:lisi
k3:v3
university:上兰村帝国技校
scala> for((k,v) <- map3) println(s"${v}<---${k}") //使用模式匹配遍历
v2<---k2
v5<---k5
v4<---k4
v1<---k1
33<---age
lisi<---name
v3<---k3
上兰村帝国技校<---university