Scala学习笔记(2)
一、控制结构和函数
---------------------------------------------------------------
1、条件表达式
(1) 在Scala中if/else的表达式都是有值的,这个值就是跟在if或者else之后的表达是的值
eg: if(x >0) 1 else -1 //上面表达式的值是1或者-1,具体是哪个值取决于x的值
(2) 可以将if/else表达式的值赋给变量
val s = if (x > 0) 1 else -1 <===>if(x>0) s = 1 else s =-1 //相对而言,前面的一种写法会更好,因为其可以用来初始化一个val,而在后面的s必须是var类型,这个地方x是常量不能再进行赋值了
java表达式:x>0?1 : -1 //Java或C++ <===>if(x > 0 )1 else -1
(3)在Scala中,每个表达式都有一个类型。举例来说,表达式if(x>0) 1 else -1 的类型是Int,因为这里的两个表达式都是Int
而:if (x>0) "positive" else -1 //这个表达式的类型是两个分支类型的公共超类。这里第一个分支是java.lang.String
而另外一个 分支是Int类型。所以这里的公共超类是Any
这里如果else部分缺失了:if (x>0) 1 //那么有可能if语句没有输出值。但是在Scal中,每个表达式都应该有某种值,这个问题的解决方案是引入一个Unit类,写作()。
不带else的if语句等同于if (x> 0 ) 1 else () //()表示的是"无有用值"的占位符,可以将Unit当做Java或C++中的void
(4)注意:REPL比起编译器来更加的"近视",在同一时间只能看到一行代码。
eg: if(x>0) 1
else if (x==0) 0 else -1 //这里REPL会执行if(x>0) 1 ,然后就显示结果,而之后看到接下来的 else 关 键 字 就会不知所措
如果想在else前面换行的话,需要用到花括号
if(x > 0){1
} else if (x==0) 0 else -1
如果想在REPL中粘贴成块的代码,而又不想近视问题,可以使用粘贴模式。键入:paste,把近视代码粘贴进去,然后按下Ctrl + D。这样REPL会把整个代码块当做一个整体来进行分析
(5)条件表达式,scala的表达式有值,是最后一条语句的值
scala>val x =1 ;
scala > val b = if (x>0) 1 else -1 ;
(6)val xx = if(x>0) 1 else "hello" //这个地方的返回值是Any类型 xx:Any =1,Any是Int和String的创造类
参数的强转: 1.toString //将数值类型的转换成字符串类型String类型
"1000".toInt //将字符串类型转换成Int类型
(7)赋值语:val y = (s =1 ) //赋值语句为空,y:Unit =() 类似于java中的void
(8)粘贴模式:scala>:paste
if(x>0) {
1 } else -1
// ctrl + D //退出粘贴模式
(8)java语言的编码运行过程:*.java ----->*.class----------->程序
2、语句终止:Scala与其他的脚本语言相类似,行尾的位置不需要分号。在}、else以及类似的位置也不需要写分号,只要能从上下文明确的判断出这里是语句的终止就可以
(1)如果在单行中能够写下多个语句,就需要用分号将他们分割开来
if ( n > 0 ) {r = r * n ; n-=1}
(2)如果写较长的语句,需要分成两行来写的话,就需要确保第一行以一个不能用作语句结尾的符号作为结尾,一般来说是比较好的选择是操作符:
s = s0 +(v - v0)* t +
0.5*(a-a0)*t*t
(3)Scala程序员们更加倾向于使用花括号来进行相关的处理:
if(n > 0){
r = r*n
n -=1
} //这个地方可以知道,以{结束的行很清楚的表示了后面还有很多的内容
3.块表达式和赋值
在java中快语句是包含在{}中的语句序列。当需要在逻辑分支或循环中放置多个动作的时候,可以使用快语句。
在Scala中,{}块包含一系列的表达式,结果也是一个表达式。快中最后一个表达式的值就是块的值
eg:val distance = {val dx = x -x0 ; val dy = y -y0 ; sqrt (dx * dx + dy * dy)}
{}块的取值取其最后一个表达式,在此处粗体标出。变量dx和dy仅作为计算所需的中间值
在Scala中,赋值动作本身是没有值的,或者说,他们的值是Unit类型的,Unit类型等价于java中的void,而这个类型只有一个值,写作()。一个以赋值语句结束的块,比如{r =r * n; n -=1)的值是Unit类型的
Unit<===>void
4、输入和输出
(1).打印一个值,需要用print或者println函数进行相关的打印,而后者在打印完成后会追加一个换行符。
print("answer:") //打印
println(43) //换行打印
//输出
Scala>print("hellp")
Scala>println("hello")
Scala>val password = readLine("请输入密码");
5、循环
Scala拥有和java相同的while和do循环
通过粘贴模式来写循环。(while)
var i = 0;
while(n>0){ r= r*n n-=1 }
通过Scala语言打印出99乘法表
var i = 1; while(i<10){ var j = 1; while(j<=i){ print(i+"*"+j+"="+(i*j)+" "); j+=1; } println(); i+=1; }
百钱买百鸡问题
//百钱买白鸡 100块钱买100只小鸡 公鸡:5块钱/只 母鸡:3块钱/只 小鸡:1块钱/3只
var cock=0;
while(cock <= 20){
var hen = 0 ;
while(hen <=100/3){
var chicken =0;
while(chicken<=100){
var money=cock*5 + hen*3 +chicken*(1/3);
var mount = cock + hen + chicken;
if(money==100 && mount==100){
println("cock:"+cock+","+"hen:"+hen+","+"chicken:"+chicken);
}
chicken+=3;
}
hen+=1;
}
cock+=1;
}
Scala加载Scala类的方法:load d:\scala\buy.scala
(2)for循环
for(x<-1 to 10) println(x)
语法: for(i<- 表达式) //这个地方1 to n 这个调用返回1到n之间的区间的Range //让变量i便利<-右边的表达式的所有制。至于这个便利具体如何执行,取决于表达式的类型。
在便利字符串或者数组的时候,通常需要使用0到n-1的区间。这个时候可以用util方法而不是to方法。util方法返回一个并不包含上限的区间。
val s ="hello" var sum = 0 for(i <- 0 util s.length){ sum +=s(i)}
println(sum);
可以使用breaks对象的break方法
6、可以使用变量<-表达式的形式提供多个生成器,用分号将其分隔开来。
for高级循环
for(i<- 1 to 3 ;j<- 1 to 3) println((10*i+j)+" ")
这个地方每一个生成器都可以带一个守卫,以if开头的Boolean表达式:
for(i<- 1 to 3 ; j <- 1 to 3 if i!=j) print((10*i+j)+" ")
如果for循环的循环体外面以yield开始,则循环会构造一个集合,每次都迭代集合中的一个值
for(i < -1 to 10) yeild i%3 //这样的for循环叫做for循环推倒式
7、函数
Scala除了方法之外还支持函数。方法对对象进行操作,函数不是,如果要定义函数,需要给出函数的名称、参数和函数体
def abs(x:Double)=if(x>=0) x else -x
如果函数体需要多个表达式完成,可以用代码块。快中最后一个表达式就是函数的返回值。
def fac(n:Int)={ var r =1 for(i<- 1 to n) r= r*i r }
本例中返回值是r,但是没有return 这个关键词
但是对于递归函数,我们必须制定返回值类型。
def fac(n:Int):Int=if(n<=0) 1 else n*fac(n-1) //这个地方的递归函数必须制定返回值类型,如果没有进行指定,Scala编译器就没有办法校验n*fac(n-1)的数据类型了
定义函数:
def add (a:Int,b:Int):Int = {
var c =a+b ;
return c;
}
在:paste模式下进行粘贴,最后会得到add(a:Int,b:Int)Int,即是参数类型是Int型,返回值类型也是Int型
定义递归:
def fac(n:Int):Int= if(n==1) 1 else n*fac(n-1); //定义了n的阶乘,递归的函数必须显示定义返回值类型
8.默认参数和带名参数
(1)eg:def decorate(str:String,left:String="[",right:String="]")= left+str+right;
如果调用decorate("hello") ===>["Hello"]
或者:def decorate(prefix:String,str:String,suffix:String)={ //默认不带参
prefix+str+suffix
}
//这个地方的调用:最少要带上两个参数,decorate("hello","world");最终把最后的括号带上了
//或者指定给哪个参数进行传参,decorate(str="hello")
//或者给其他的参数进行相关的传参:scala>decorate(str="hello",prefix="<<"。最后的返回值是<<hello[]]
def decorate(prefix:String="[[",str:String,suffix:String="]]")={ //默认带参数的
prefix+ str+suffix
}
调用函数decorate("[[","hello","]]") ==============>[[hello]]
(2)如果相对参数的数量的值不够,参数会从后面诸葛应用进来,如decorate("Hello",">>>")会使用right参数的默认值,
得到">>>[Hello]"
def sum(args:Int*)={ var result = 0 for(arg <- args) result+=arg result }
(3)在提供参数值的时候指定参数名。如:
decorate(left="<<<",str="Hello",right=">>>") //最后的结果是<<<Hello>>>
(4)带名参数可以让函数更加可读。
(5)函数的默认值和命名参数
scala>def decorate(prefix:String,str:String,suffix:String)={
prefix + str +sufix
}
9.变长参数
(1)边长参数用法例子
def sum(args:Int*)={ var result = 0 for(arg<-args) result+=arg result }
val s = sum(1,4,9,16,25) //这个地方函数得到的是一个类型为Seq的参数
(2)如果已经有一个值的序列,则不能直接将其传入函数。如:var s =sum(1 to 5) //错误
val s = sum (1 to 5) //错误,这个地方要注意,如果sum函数传入的是单个参数,那么参数必须是单个的整数,而不是一个整个的区间。解决的办法是告诉编译器,希望这个参数被当做参数序列进行处理。追加:_*,如下所示:
val s =sum(1 to 5:_*) //这个地方将1 to 5当做参数序列进行处理
(3)在递归定义中会用到上面的语法:
def recursiveSum(args:Int*):Int={ //在这里序列head是首个元素,而tail是所有其他元素的序列,这又是一个Seq,我们用_*来转换成参数序列
if(args.length==0) 0
else args.head + recursiveSum(args:tail:_*)
}
(4)参数当做参数序列进行处理
def sum1(args:Int*):Int={ if(args.length==0) 0 else args.head+sum1(args.tail_*) }
scala>add(1 to 10) //错误
scala>add(1 to 10:_*) //将1 to 10当做序列
10.过程:如果函数体包含在花括号中但是没有前面的=号,那么返回值类型就是Util。这样的函数成为过程
过程不返回值,我们调用它仅仅是为了副作用
(1)也可以进行这样的方式进行相关的定义:def box(s:String):Unit={
................
}
def box(s:String){ //仔细看:这个地方没有=号 var border="-" * s.length +"--\n" println(border+"|"+s+"\n"+border) }
11.懒值
当val被声明为lazy的时候,它的初始值将被推迟,知道我们首次对其进行取值
lazy val words =
12.异常处理
try{
"hello".toInt;
}catch{
case _:Exception =>print("xxx");
case ex:java.io.IOException=>print(ex)
}
_ //通配符
java.io._ //通配相当于*
:_* //1 to10:_*,转成序列