scala解释器
- scala解释器也被称为REPL,会快速编译scala代码为字节码文件,然后交给JVM类执行
read(取值)evaluate(求值)print(打印)loop(循环) - 计算表达式:在scala>输入scala代码,解释器会直接返回结果(进入scala>: win+R -> cmd -> scala.bat)
- 如果没有指定变量来存放值,那么值默认的默认名称为res,并显示结果的数据类型
- 内置变量 在后面可以继续使用res这个变量
- 可以使用Tab进行自动补全
声明变量
- val变量
可以声明val变量来存放表达式计算结果的值,但是之后就无法修改(类似java中的final修饰的常量) - var变量
var变量存放的值可以修改,在scala中建议大量的使用val - 无论是val还是var,都可以手动指定类型,如果不指定的话,scala会根据值进行类型推断
数据类型与操作符
- 基本数据类型(Byte,Char,Int,Long,Float,Double,Boolean)
scala的数据类型统一都是类,指定进行基本数据类型和引用类型的转换操作,并且可以调用大量的函数(1.toString(),1.to(10)看不懂没关系,后面后的是机会让你看懂) - 加强版类型:很多加强类型给基本数据类型增加了上百种增强的功能或函数
- String类通过StringOps类增强了大量的函数"hello".intersect("world")
- 还提供了RichInt,RichDouble,RichChar等类型
- 基本操作符
和Java的算术操作符基本没有区别但是scala没有++、–操作符
调用函数
除了方法外,scala还提供了函数
数学函数:sqrt() pow() min()
引入特定包是使用:import 包名._
例: import scala.math._( _:通配符,类似Java中的 *)
if
在scala中if表达式是有值的,就是if或else中最后一行语句的返回的值
- 可以将if表达式赋予一个变量
val aa = if(age>18) 1 else 0
或
var aa=-1;
if(age>18) aa=1 else aa=0
- if表达式的类型推断if ,else子句的值得类型可能是不同的,scala回取两个类型的公共父类型
if(age>18) "aa" else 0
//此时if和else的值得类型分别是String和Int,则表达式的值得类型是Any
如果if后没有else,则默认else的值是Unit,也可以用()表示(类似Java中void或null)
//意思相同的两种个写法
val age =10 ; if (age>10) " adult"
val age =10 ; if (age>10) " adult" else() //else的值是Unit,也可以用()表示
默认情况些,REPL只能解释一行语句,但if表达式要放在多行,可以使用{ }
或者使用 :paste /ctrl+D(退出)方式
默认情况下scala不需要语句终结符,默认将每一行作为一个语句
一行放多条语句,使用;分隔,
var a,b,c =0; if(a<10) { b=b+1;c=c+1}
或
var a,b,c
if(a<10){
b=b+1
c=c+1
}
块表达式:{ } 中的值,其中包含多条语句,最后一条语句就是表达式的返回值
输入和输出
print 和println:和java一样 ,println打印时会加一个换行符
printf:可以用于进行格式化
printf("hi,my name is %s,i am %d years old.\n","Tom",30)
reaLine:允许我们从控制台读取用户输入的数据,类似java中的System.in和Scanner的作用
循环
scala拥有和java一样的while和do-while循环
for循环和java有区别
for(i<-表达式) //让变量i遍历右边的表达式的所有值
在for循环的变量之前并没有val或var的指定,该变量的类型是集合的元素类型
循环变量的作用于一直持续到循环结束
until方法返回一个不包含上限的区间
使用;分隔多个生成器
for(i<- 1 to 3;j<- 1 to 3) print ((10*i+j)+" ") //使用;分隔多个生成器
在for循环中添加过滤条件if语句,称为守卫式
for( i<- 1 to 3 ; j<- 1 to 3 if i!=j) print((10*i+j)+" ") // if前面没有;
在循环中使用变量
for( i<- 1 to 3 ;from=4-i ;j<- from to 3) print((10*i+j)+" ")
推导式
如果for循环的循环体以yield开始,该循环会构造出一个集合,每次迭代生成集合中的一个值
for(i<- 1 to 10) yeild i%3
函数
在代码块中定义包含多行语句的函数体
//单行函数
def say(name:String)=print("hello"+ name)
//多行函数
def sum(n:Int):Int={
var sum=0;
for(i<- 1 to n) sum+=i
sum //返回值
}
在scala中定义函数时,需要定义函数的函数名,参数,函数体
必须给出所有参数的类型,但是不一定给出函数的返回值的类型,只要右侧的函数体中不包含递归的语句,scala就可以执行推断出返回类型
- 递归函数
函数体内递归调用函数自身
//斐波那契数列
def fab(n:Int):Int={
if(n<=2) 1
else fab(n-1)+fab(n-2)
}
- 默认参数
在调用某些函数是,不希望给出参数的具体值,希望采用参数自身的值,就是用定义时定义的默认参数的值
在调用函数时,可以不按照函数定义的顺序来传递参数,使用 参数名="参数值"
还可以混用,未命名的参数必须放在前面 - 使用序列调用可变长参数
val s = sum(1 to 5:_*) //:_*转换成参数序列
//使用递归函数实现累加
def sun(num:Int*):Int={ //num:Int*:任意多个num:Int
if(num.length==0)0
else nums.head+sum(name.tail:_*) //第一个数与除了第一个数字外的全部数相加
}
- 过程
定义函数时,函数体直接包裹在{ }中,没有使用=连接,则函数的返回值类型就是Unit,称之为过程
def say(name:String)="hello"+name
def say(name:String){print("hello"+name);"hello,"+name}
def say(name:String):Unit="hello"+name
- lazy 值
如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算
数组
//固定长度使用Array
val aa = new Array[String](10)
//不固定长度使用ArrayBuffer
import scala.collection.mutbale.ArrayBuffer
val ss= new ArrayBuffer[Int]
//数组的基本操作
ss+=1
ss+=(1,2,3,4,5)
ss++=Array(12,15,18)
ss.trimEnd(3) //删除最后3个元素
ss.insert(2,5) //从索引2的地方加入元素5
ss.insert(2,5,6,7) //从索引2的地方加入元素5 6 7
ss.remove(2) //删除索引为2的元素
ss.remove(2,5) //从索引为2的地方开始删除5个元素
变长数组 -> 定长数组:toArray
定长数组 -> 变长数组:toBuffer
- 遍历数组
for(i<-(0 until ss.length) print(ss(i)+" ") //正常遍历
for(i<-(0 until ss.length).reverse print(ss(i)+" ") //逆序遍历
for(i<-(0 until (ss.length,2) print(ss(i)+" ") //跳跃遍历,隔一个
for(i<-(elem->ss) print(elem) //
- 常用算法
val aa =Array(3,5,9,7,8,6)
val aa1= aa.sorted
val aa2=aa.sortWith(_>_)
val aa3=aa.sortWith(_<_)
aa.mkString //将数组中的额每一个元素相连接
aa.mkString("XXX") //使用XXX将数组中的额每一个元素相连接
映射
Scala中的映射就是键值对对的集合Map,默认情况下Scala中使用不可变的映射
(如果想使用可变集合Map,必须导入scala.collection.mutable.Map)
var aa=Map("Alice"->10,"Tom"->25) //可变集合
val bb=scala.collection.mutbale.Map("Tony"->23,"Amy"->18) //不可变集合
- 映射这种数据结构是将键映射到值得函数
- 区别在于通常的函数计算值,而映射只是做查询
scala中集合分成三大类
- 序列(Seq)
- 集(Set)
- 映射(Map)
//不可变
val aa=Map ("tom"-> 20,"jack"->18, "sam"->25)
//不可变
val aa=Map (("tom",20),(“jack",18),("sam",25))
//可变
val bb=scala.collection.mutable.Map(("tom",20),("jack",18),("sam",25))
//获取映射中的值
val cc=aa("william") //如果映射不包含请求中的值,会抛异常
val cc=aa("Tom")
val cc= if (aa.contains("Tom")) aa("Tom") else 0 //检查映射中是否有某个指定的键
val cc=aa.getOrElse("Tom",0) //如果包含相应的键,返回这个件所对应的值,否者返回0
//映射.get(键)这样的调用返回一个option对象,要么是Some(键对应的值),要么是NONE
- 修改Map的元素
可变Map集合
//更新Map的元素
bb("Amy")=50
//增加多个元素
bb+=("mike"->35)
//移除元素
bb-="mike"
修改不可变Map集合
//添加元素,产生一个新的集合Map,原Map不变
val cc =aa+("mike"->36)
//移除元素,产生一个新的集合Map,原Map不变
val cc =aa-"mike"
遍历Map操作
//遍历map的entry
for((key,value)<-aa) println(key+" "+value)
//遍历map的key
for(key<-aa.keySet) println(key)
//遍历map的value
for(value<-aa.values) println(value)
//生成新的map,翻转key,value
for((key,value)<-aa) yield(value,key)
//SortedMap可以自动对map的key排序
val cc=scala.collection.immutable.SortedMap("mike"->55,"Alice"->10,"Tom"->25)
//LinkedHashMap可以记住插入entry的顺序
val cc = new scala.collection.mutable.LinkedHashMap[String,Int]
cc("Alice") =10
cc("Tom") =25
cc("mike") =55
javaMap和ScalaMap的隐式转换
//Java map to scala map
import scala.collection.JavaConversions.mapAsScalaMap
val cc =new java.util.HashMap[String,Int]()
cc.put("Tom",10)
cc.put("Amy",20)
cc.put("sam",30)
val ss:scala.collection.mutable.Map[String,Int]=cc
//scala map to java map
import scala.collection.JavaConversions.mapAsJavaMap
import java.awt.font.TextAttribute._
val rr =Map(FAMILY->"aa",SIZE->2)
val font=new java.awt.Font(rr)
元组
- 元组是不同类型的值得聚集
- 对偶是元组的最简单性形态
元组的索引是从1开始(不是0,不是0,不是0)
val tuple=(2,5.5,"Tom")
val second=tuple._2
- 拉链操作
即zip操作,是Array类的方法,将两个Array合并成一个Array
Array(v1)和Array(v2),合并后的格式为Array((v1,v2)),合并后的元素类型为Tuple
(多的直接删掉)
val aa=Array("a","b","c")
val bb=Array(1,2,3)
val cc=aa.zip(bb)
for((aa,bb)<-cc)
println(aa+" "+bb)
经典面试题
移除第一个负数后的所有负数
//基本款
var array=ArrayBuffer[Int]()
array+=(1,2,3,4,5,-6,7,8,9,-1,-2,-3,-4)
var arraylength=array.length
var a=0
var index=0
while(index<arraylength){
if(array(index)>=0){
index+=1
}else{
if(a>0){array.remove(index);arraylength-=1}
else{a+=1;index+=1}
}
}
//优化款
var array=ArrayBuffer[Int]()
array+=(1,2,3,4,5,-6,7,8,9,-1,-2,-3,-4)
var a=0
val keepindex=for(i <- 0 until array.length if a<1 ||array(i)>=0) yield { if(array(i)<0) a+=1;i }
for(i <- 0 until keepindex.length) {
array(i)=array(keepindex(i))
}
array.trimEnd(array.length-keepindex.length)
高阶函数
把函数当做参数的函数
filter
完整版:arrary.filter(m=>m%2==0) //匿名参数m=>m%2==0
简单版:arrary.filter(_%2==0)
匿名函数:
def test (m:Int)={m%2==0} => m =>{m%2==0}
只有一个参数可以删除()
数据类型可以删掉