文章作者郵箱:yugongshiye@sina.cn? ? ? ? ? ? ? 地址:廣東惠州
?▲ 本章節目的
??掌握Scala的基礎語法;
? 掌握Scala的函數庫;
一、Scala 基礎語法一
1. 概述
語句 | 說明 | 示例 |
var | 用來聲明一個變量, | ?def main(args: Array[String]): Unit = { ??? var var1=100 ??? var var2:Int=100 ?? //變量修改 ??? var2=200; ??? var3="world"; |
val | 用來聲明一個常量, ? | //定義常量,但不允許修改常量 val vall = 100; //常量修改將報錯 vall = 200; |
操作符 | scala中操作符即方法,方法即操作符 所以 可以認為 scala中并沒有傳統意義上的操作符 所有的操作符都是方法 所有的方法也都可以像操作符一樣去使用 | 1.?算術運算符 + - * / % 2.?關系運算符 ==? !=? >?? <?? >=? <=== > < >= <= 3.?邏輯運算符 &&? ||? ! 4.?位運算符 ~? &? |? ^? <<?? >>?? >>> 5.?賦值運算符 =? +=? -=?? *=?? /=?? %= |
2. 算術運算符
下表列出了Scala支持的算術運算符。
假定變量A為10,B為20:
運算符 | 描述 | 實例 |
+ | 加號 | A + B 運算結果為 30 |
- | 減號 | A - B 運算結果為 -10 |
* | 乘號 | A * B 運算結果為 200 |
/ | 除號 | A / B 運算結果為 2 |
% | 取余 | A % B 運算結果為 0 |
3. 關系運算符
下表列出了Scala支持的關系運算符。
假定變量A為10,B為20:
運算符 | 描述 | 實例 |
== | 等于 | ( A == B ) 運算結果為 false |
!= | 不等于 | ( A != B ) 運算結果為 true |
> | 大于 | ( A > B ) 運算結果為 false |
< | 小于 | ( A < B ) 運算結果為 true |
>= | 大于等于 | ( A >= B ) 運算結果為 false |
<= | 小于等于 | ( A <= B ) 運算結果為 true |
4. 邏輯運算符
下表列出了Scala支持的關系運算符。
假定變量A為1,B為0:
運算符 | 描述 | 實例 |
&& | 邏輯與 | ( A && B ) 運算結果為 false |
|| | 邏輯或 | ( A || B ) 運算結果為 true |
! | 邏輯非 | ! ( A && B ) 運算結果為 true |
5. 位運算符
位運算符用來對二進制位進行操作,~,&,|,^ 分別為取反,按位與與,按位與或,按位與異或運算,如下實例:
運算符 | 描述 | 實例 |
& | 按位與運算符 | (a & b) 輸出結果12,二進制解釋:0000? 1100 |
| | 按位或運算符 | (a | b) 輸出結果61,二進制解釋:0011? 1101 |
^ | 按位異或運算符 | (a ^ b) 輸出結果49,二進制解釋:0011? 0001 |
~ | 按位取反運算符 | (~a) 輸出結果-61,二進制解釋:1100? 0011, 在一個有符號二進制數的補碼形式。 |
<< | 左移動運算符 | a<<2 輸出結果240,二進制解釋:1111? 0000 |
>> | 右移動運算符 | a>>2 輸出結果15,二進制解釋:0000? 1111 |
>>> | 無符號右移 | a>>>2 輸出結果15,二進制解釋:0000? 1111 |
6. 賦值運算符
一下列出了Scala語言支持的賦值運算符:
運算符 | 描述 | 實例 |
= | 簡單的賦值運算,指定右邊的操作數賦值給左邊的操作數。 | C = A + B 將 A + B 的運算結果賦值給 C |
+= | 相加后再賦值,將左右兩邊的操作數相加后再賦值給左邊的操作數。 | C += A 相當于 C = C + A |
-= | 相減后再賦值,將左右兩邊的操作數相減后再賦值給左邊的操作數。 | C -= A 相當于 C = C - A |
*= | 相乘后再賦值,將左右兩邊的操作數相乘后再賦值給左邊的操作數。 | C *= A 相當于 C = C * A |
/= | 相除后再賦值,將左右兩邊的操作數相除后再賦值給左邊的操作數。 | C /= A 相當于 C = C / A |
%= | 求余后再賦值,將左右兩邊的操作數求余后再賦值給左邊的操作數。 | C %= A 相當于 C = C % A |
二、Scala 基礎語法二
語句 | 說明 | 示例 |
if……else | if……else 判斷 if是具有返回值的,if判斷后,將執行代碼的最后一個表達式的值返回作為整個if執行后的結果。 | ??? //一個簡單的示例 ??? var var1=10; ??? if(var1<100){ ????? println("小了") ??? }else{ ????? println("大了") ??? } ??? ?? ?//根據scala函數式編程風格,建議做如下更改 ??? //盡量使用常量 ??? val val1=10; ?? ?//if……else最后一行的值是返回值,可省略return ??? val result= ???????? if(val1<100){ ?????????? "小了"; ???????? }else{ ?????????? "大了"; ???????? } ??? print(result) ??? //也可以簡化成下面的形式 ??? val val2=10; ??? println(if(val2<100)"小了"else"大了"); |
while | 和java中用法相同 | ??? //一個簡單的例子 ??? val val1=List(1,2,3,4); ??? var index=0; ??? while(index<val1.size){ ????? println(val1(index)); ????? index+=1; ??? } |
for | scala中的for要比java的for強大,使用很頻繁,需要熟練掌握。 ? | ?? //生成一個1~100的區間,區間類型是range ??? val val1=1 to 100; ??? ??? //循環遍歷并打印 ??? for(num <-val1){ ????? println(num) ??? } ??? ??? //支持條件過濾 ??? for(num<-val1;if num>50){ ????? println(num) ??? } ??? ??? //支持多條件過濾 ??? for(num<-val1;if num>50;if num%2==0;if num<90) ????? println(num) ?? //也可以寫成下面的形式 ??? for(num<- 1 to 100;if num>50&&num<90&&num%2==0){ ????? println(num) ??? } |
try catch finally | scala中繼承了java的異常機制 | import java.lang try { ????? throw new RuntimeException("error"); ??? }catch { ?????? case t: NullPointerException => t.printStackTrace();("空指針異常"); ????? case t: Exception=>t.printStackTrace();println("其他異常"); ??? }finally { ????? println("資源釋放") ??? } |
match | scala中的match類似于其他語言的switch | //一個簡單的例子 //match匹配到case后,執行case對應的內容,然后退出match,于java不同的是,不需要寫break ??? val val1="bbb"; ??? val1 match { ????? case "aaa" =>println("1"); ????? case "bbb" =>println("2"); ????? case? _ =>println("3"); ??? } ??? ? ??//此外,match可以帶有返回值 ??? val result=val1 match{ ????? case "aaa" =>1 ????? case "bbb" =>2 ????? case? _ =>3 ??? } |
break continue | scala中沒有break和continue語句,需要通過另外的形式來實現 | import util.control.Breaks._ object Demo12 { ? def main(args: Array[String]): Unit = { ???? ??? ?//實現break ? ???breakable( ?? for(i <- 1 to 10){ ?????? if(i==8){ ????????? break(); ?????? }else{ ???????? println(i); ?????? } ???? } ????? ???) ???? ??? ?//實現continue ???? for(i<-1 to 10){ ?????? breakable( ??????? if(i==8){ ????????? break; ??????? }else{ ????????? println(i); ??????? } ???? ??) ???? } ???? ???? ? } } |
三、Scala函數上篇
1. 函數聲明
scala 函數通過 def 關鍵字定義,def前面可以具有修飾符,可以通過private、protected來控制其訪問權限。
注意:沒有public,不寫默認就是public的。 此外也可跟上override,final等關鍵字修飾。
2. 函數返回值
1. 函數體中return關鍵字往往可以省略掉,一旦省略掉,函數將會返回整個函數體中最后一行表達式的值,這也要求整個函數體的最后一行必須是正確類型的值的表達式。
2. 大部分時候scala都可以通過 =符號 來自動推斷出返回值的類型,所以通常返回值類型聲明可以省略。
但是注意:如果因為省略了返回值類型造成歧義,則一定要寫上返回值聲明。
3. 如果函數體只有一行內容,則包裹函數體的大括號可以省略
4. 如果返回值類型是UNIT,則另一種寫法是可以去掉返回值類型和等號,把方法體寫在花括號內,而這時方法內無論返回什么,返回值都是 UNIT。????????????????
格式:[private/protected] def 函數名(參數列表):返回值聲明 = {函數體}
示例:
? //方法的返回值為空
? def f1():Unit={
???? println("hello scala");
? }
? //等價于f1()方法,注意:如果函數沒有=號,無論函數體里的返回值是什么,函數的返回值都是Unit
? def f2(){
??? println("hello scala");
? }
? //定義方法參數類型,返回值類型,及返回值
? def f3(a:Int,b:Int):Int={
??? a+b;
? }
??//scala可自行推斷返回值類型,所以可省略返回值類型
? def f4(a:Int,b:Int)={
??? a+b;
? }
? //如果函數體只一行內容,可以省了花括號
? def f5(a:Int,b:Int)=a+b
? //注意下面這種形式,因為沒有=號,所以函數的返回值是Unit,即()
? def f6(a:Int,b:Int){
??? a+b
? }
3. 默認參數
代碼示意:
object Demo21 {
? def f1(a:String,b:String="[",c:String="]")={
??? b+a+c
? }
? def main(args: Array[String]): Unit = {
??? print(f1("hello"))//將打印:[hello]
? }
}
4. 函數的種類
1.成員函數
2.本地函數(內嵌在函數內的函數)
3.函數值(匿名函數)
4.高階函數
成員函數: 函數被使用在類的內部,作為類的一份子,稱為類的成員函數
示例:
object Demo15 {
? def main(args: Array[String]): Unit = {
??? val p=new Student();
??? p.eat();
??? p.study();
? }
? // eat() 和study()屬于 類Student的成員函數
? class Student{
??? def eat(){
????? println("吃飯")
??? }
??? def study(){
????? println("學習")
??? }
? }
}
本地函數:函數內嵌的函數稱為本地函數,這樣的函數外界無法訪問
示例:
object Demo16 {
? def main(args: Array[String]): Unit = {
??? val p=new Student();
??? p.eat("肉");
? }
? class Student{
??? def eat(food:String){
??? ??//cook函數內嵌在eat函數里,這樣的函數稱之為本地函數
????? def cook(food:String):String={
??????? "做熟了的"+food;
????? }
????? println("吃"+cook(food));
??? }
? }
}
函數值 - 匿名函數:
示例:
??? def f1(a:Int,b:Int):Int={a+b};
??? //等價于上式的函數
??? (a:Int,b:Int)=>{a+b};
??? //如果函數體只有一行代碼,可以省去大括號
??? (a:Int,b:Int)=>a+b;
? ??//如果函數參數列表只有一個參數,小括號有可以省略
??? a:Int=>a+1;
??? //如果函數的參數類型可以被推測,則可以省略類型值
??? //(a,b)=>a+b
??? def f1(a:Int,b:Int):Int={a+b};
? ??//可以將f1()函數賦值給f2常量
??? val f2=f1(_,_);
??? //可以將f1()函數賦值給f3變量,f3可以更改此函數
??? var f3=f1(_,_);
??? f3=(a:Int,b:Int)=>a*b;
??? //也可以這樣寫
??? val f4=(c:Int,d:Int)=>{c+d}
? ??//注意,下面的寫法是將f1的函數值復制給f5,而不是函數賦值給f5
??? val f5=f1(2,3)
四、Scala函數下篇
1. 高階函數:
高階函數(Higher-Order Function)就是操作其他函數的函數。
Scala 中允許使用高階函數, 高階函數可以使用其他函數作為參數,或者使用函數作為輸出結果。
示例1:
object Demo01 {
? //定義了compute函數,a,b和f函數? 三個參數。其中f函數未做實現。
? //我們的目的是對傳入的a和b參數利用 f函數做運算,但是具體是什么運算需要由用戶自己來指定。
? def compute(a:Int,b:Int,f:(Int,Int)=>Int):Int={
?? f(a,b)
? }
? def main(args: Array[String]): Unit = {
??? val f1=(a:Int,b:Int)=>{a+b}
??? val f2=(a:Int,b:Int)=>{a*b}
??? val f3=(a:Int,b:Int)=>{a-b}
??? val f4=(a:Int,b:Int)=>{a/b}
??? //由下式可以看出,scala中,函數可以當做參數進行傳遞和調用
??? val result=compute(2,3,f1)
? ??//下式等價于上式
??? //val result=compute(2,3,(a,b)=>{a+b})
? }
}
示例2:
object Demo02 {
??//定義了一個函數,作用是將用戶處理后的字符串結果進行打印輸出
? def handleString(a:String,f:(String)=>String){
??? println("處理完后的字符串為:"+ f(a))
? }
? def main(args: Array[String]): Unit = {
??? val a="hello scala";
??? handleString(a,(a)=>{a});
??? handleString(a,(a)=>{a.substring(6)});
??? handleString(a,(a)=>{a.concat(" 1706")})
? }
}
占位符:占位符指的是scala中的下劃線_ ,可以用它當作一個或多個參數來使用。
使用_占位符的前提要求:每個參數在函數僅出現一次。
使用下劃線時,如果類型可以自動推斷出,則不用聲明類型。如果無法自動推斷類型,則在下劃線后自己來顯示聲明類型即可。
示例1:
object Demo03 {
? def compute(a:Int,b:Int,f:(Int,Int)=>Int):Int={
?? f(a,b)
? }
? def handleString(a:String,f:(String)=>String){
??? println("處理完后的字符串為:"+ f(a))
? }
? def main(args: Array[String]): Unit = {
??? val message="hello scala";
??? //這樣用占位符會報錯
??? //handleString(message,(_)=>{_.substring(6)})
??? //應改為下面的寫法
??? handleString(message,{_.substring(6)})
?? ?//如果函數體只有一行代碼,則還可以將大括號去掉
???? handleString(message,_.substring(6))
?? ?//compute的代碼可簡化如下?
??? compute(2,3,_+_)
??? compute(2,3,_*_)
??? compute(2,3,_-_)
?? ?//??? 此外
??? //??? val f1=(a:Int,b:Int)=>{a+b}
??? //??? 等價于下式:
??? //??? val f1=(_:Int)+(_:Int)
??? //??? compute(2, 3, f1)
??? //再來看一個例子
??? val list=List(1,3,5,7,9)
??? list.foreach { x =>print(x) }
??? list.foreach { _ =>print(_) }
??? list.foreach { print(_) }
??? list.foreach { x => x*2 }
??? list.foreach { _*2 }
? }
}
2. 遞歸函數
示例1:用遞歸方式實現斐波那契數列
?//0? 1?? 1?? 2? 3? 5? 8?? 13
?def f2(n:Int):Int={
if(n==0) return 0
if(n==1) return 1
else f2(n-1)+f2(n-2)
?}??
五、練習題
1.針對下列Java循環編寫一個Scala版本:
for(int i=10;i>=0;i–)
???? System.out.println(i);
2.編寫一個函數countdown(n:Int),打印從n到0的數字
3.編寫函數計算x的n次方,其中n是整數,要考慮等n是0,正偶數,正奇數,負數這幾種情況。
比如當x=2時,此函數要算出 2^4,2^3,2^0,2^(-1)對應的值
mi(x:Int,n:Int):Double={??? }
mi(2,10)=1024
mi(2,-1)=0.5
4.編寫一個循環,將整數數組中相鄰的元素置換
Array(1,2,3,4,5,6)
得到的結果:214365
5.創建一個Map,包含一些你想要的一些裝備,以及他們的價格。然后通過yield 構建另一個Map映射,采用同一組鍵,但是價格上打9折
比如定義一個Map:
var m1=Map("book"->10,"gun"->100,"ipad"->1000)?
則輸出的新map(m2)為:Map("book"->9,"gun"->90,"ipad"->900)?