scala程序開發入門

scala程序開發入門,快速步入scala的門檻:java

一、Scala的特性:

A、純粹面向對象(沒有基本類型,只有對象類型)、Scala的安裝與JDK相同,只須要解壓以後配置環境變量便可;
B、Scala在安裝以前必須先安裝JDK,由於Scala的編譯結果是中間字節碼文件,它須要在JVM上運行,Scala能夠調用Java類庫來完成某些功能;
C、Scala相似於python,一半面向過程一半面向對象,還能夠基於shell的命令行進行操做,固然也能夠像Java那樣先使用scalac編譯成中間字節碼以後再使用scala解釋執行它,注意保存的Scala源文件名稱必須以scala做爲擴展名,且文件名必須與對象名徹底匹配;
D、Scala相似於JS腳本,區分大小寫,以換行符爲單位來定義語句,可是若是須要在同一行定義多條語句則必須使用分號隔開;
E、執行速度對比:C(C++)>Java(Scala)>Python(Ruby);
F、Scala數據類型:
Byte(1byte)、Short(2byte)、Int(4byte)、Long(8byte)、Float(4byte)、Double(8byte)、Char(2byte)、String(取決於字符數量)、Boolean(1byte)、Unit(至關於void)、Null(至關於null)、Nothing(全部類的子類型)、Any(全部基本類型和引用類型的根類型)、AnyVal(全部基本類型的超類型)、AnyRef(全部引用類型的超類型)。python

//null值只能被推斷爲Null類型,null表明空值,它能夠被賦值給任何AnyRef類型的常量或變量
scala> var kk=null 
kk: Null = null

//定義Boolean類型
scala> val flag=true
flag: Boolean = true

//定義Char類型 
scala> val flag='A'
flag: Char = A

//小數默認推斷爲Double類型
scala> val height=1.67 
height: Double = 1.67

//整數默認推斷爲Int類型
scala> val age=30 
age: Int = 30

//定義字符串類型(字串常量必須使用雙引號),顯示的結果類型爲String,它是java.lang.String的縮寫形式
scala> val name="mmzs" 
name: String = mmzs

//Int類型能夠自動向上轉型爲超類型AnyVal
scala> val age2:AnyVal=age
age2: AnyVal = 30
//String類型爲引用類型,不能上轉型到AnyVal,由於它們之間沒有繼承關係
scala> val name2:AnyVal=name 
<console>:12: error: the result type of an implicit conversion must be more specific than AnyVal
val name2:AnyVal=name
^
//可是能夠自動上轉型爲超類型AnyRef,由於AnyRef是全部引用類型的超類型
scala> val name2:AnyRef=name 
name2: AnyRef = mmzs
//一樣的,Int爲基本類型,也不能上轉型到AnyRef,由於它們之間沒有繼承關係
scala> val age2:AnyRef=age 
<console>:12: error: the result type of an implicit conversion must be more specific than AnyRef
val age2:AnyRef=age
^
//可是全部的基本類型(AnyVal)和引用類型(AnyRef)均可以自動上轉型爲根類型Any    
scala> val kkm:Any=age
kkm: Any = 30
scala> val kkm:Any=name
kkm: Any = mmzs
scala> val kkm:Any=age2
kkm: Any = 100
scala> val kkm:Any=name2
kkm: Any = mmzs
scala>:quit //也能夠直接:q

注意:
對任何Scala對象的顯式類型定義其前面都有一個以英文冒號做爲前綴的類型標註,這是Scala的語法所決定的,如:val abc:Int=12三、def getName():String={............}
8中基本類型都是scala核心包中的,scala包至關於Java中的java.lang包
Scala是強類型的語言,並非弱類型語言,雖然你並無顯式指定變量的類型,可是Scala會根據你賦的值自動進行類型推斷,一旦推斷出變量的類型,後續使用該變量就必須符合類型兼容原則
定義變量或函數的通式是:val[var|def] varName|funName(...):type=value|{.....} 程序員

G、字面常量:
單引號:表示單個字符
雙引號:表示字符串
三雙引號:表示具有可換行的多行字符串es6

//三雙引號實例
scala> val info="""my name is mmzs
| my age is 30"""
info: String =
my name is mmzs
my age is 30    

H、字符串之間以及字符串與變量、表達式之間的拼接直接使用重載的加號("+")
I、Scala中沒有static的概念,全部處於object定義對象中的成員都是靜態的,入口方法main必須被定義在object定義的類中,同時源文件的名字必須與object定義的對象名同名,一個源文件中可使用class定義多個類,
也可使用object定義多個對象,可是做爲運行的入口main方法永遠都是處於與源文件名相同的對象體內
J、Scala中的全部常量和變量(包括成員常量、變量和局部常量、變量)都必須先定義和初始化而後才能被使用,暫時不能肯定值的常量、變量能夠被初始化爲空值(即0,初始化爲0意味着數字類型被賦值爲0,字符類型被賦值爲空格、布爾類型被賦值爲false,引用類型所有被賦值爲null),如:sql

scala> var age:Int=0
age: Int = 0
scala> var height:Double=0
height: Double = 0.0
scala> var code:Char=0
code: Char = ?
scala> var flag:Boolean=false
flag: Boolean = false
scala> var name:String=null
name: String = null

二、基礎語法:

A、變量的聲明:

//聲明變量(變量的值能夠被從新賦值以改變它的值)
var VariableName:DataType=Initial Value
//聲明常量(常量的值不能夠被從新賦值,值不能被改變)
val VariableName:DataType=Initial Valueshell

//val定義的是常量,不能被從新賦值,可是可使用val從新定義它,如:
scala> val ab=20
ab: Int = 20 //自動推斷爲Int類型
scala> ab=50 //此處常量ab不能被從新賦值
<console>:12: error: reassignment to val
       ab=50
         ^
scala> val ab=50 //可是能夠從新定義該常量
ab: Int = 50

//var定義的是變量,能夠被從新賦值,如:
scala> var ab=220
ab: Int = 220
scala> ab=50 //此處ab變量被從新賦值
ab: Int = 50
scala> var ab=50.05 //也能夠被從新定義
ab: Double = 50.05

//val與var定義的常量或變量均可以相互被對方重定義,重定義時能夠被定義成其它類型
scala> val ab=100
ab: Int = 100
scala> var ab=true
ab: Boolean = true
scala> val ab='A'
ab: Char = A     
scala> var ab=45.55
ab: Double = 45.55
scala> ab=true //變量的值能夠被從新賦值,可是所賦的值必須與定義該變量時的類型匹配
<console>:12: error: type mismatch;
 found   : Boolean(true)
 required: Double
       ab=true
          ^
scala> ab='A' //隱式將Char類型按ASCII碼轉換成Double類型,這是符合自動類型轉換規則的ab: Double = 65.0    

B、變量的類型與賦值表達式

  在 Scala 中聲明變量和常量不必定要指明數據類型,在沒有指明數據類型的狀況下,其數據類型是經過變量或常量的初始值來進行推斷,能夠看出Scala語言其實是一種強類型的編程語言,Scala聲明變量的語法有點相似於JS但與JS也有區別,區別在於JS中的var關鍵字不是必須的,且JS中的每個變量能夠自由靈活的被賦值爲任何類型的值;可是Scala語言中的var或val關鍵字是必須的,且一旦使用這些關鍵字定義了變量或常量的類型(根據定義時的初始值進行類型自動推斷)以後,後續對該變量的賦值就必須符合類型兼容原則,若是該變量須要被賦值爲其它類型則只能使用val或var對其從新定義編程

var myVar = 10;//聲明變量
val myVal = "Hello,Scala!";//聲明常量
//以上實例中,myVar 會被推斷爲Int類型,myVal會被推斷爲String類型
//使用枚舉法同時聲明多個相同類型和值的變量
scala> val a,b=100 //a,b都聲明初始值爲100,都被推斷爲Int類型
a: Int = 100
b: Int = 100
scala> a
res1: Int = 100
scala> b
res2: Int = 100
//使用元組法同時聲明多個不一樣類型和值的變量 
scala> val (a,b)=(100,"mmzs")
a: Int = 100
b: String = mmzs
//使用元組法時也能夠顯式指定類型
scala> val (a:Int,b:String)=(100,"mmzs")
a: Int = 100
b: String = mmzs
//注意下面這種方式其實是枚舉法的賦值方式,它表示將右邊的元組對象同時賦值給左邊的a和b兩個變量
scala> val a,b=(100,"mmzs")
a: (Int, String) = (100,mmzs)
b: (Int, String) = (100,mmzs)

C、Scala命令行換行
C一、可使用三雙引號輸入多行數據
C二、若是輸入了錯誤的內容致使命令等待能夠連續兩次回車以結束輸入數組

D、函數定義

def max(a:Int,b:Int):Int={
  ......
}

說明:
函數定義以def開始,函數參數名後面必須指定類型,由於Scala沒法自動推斷出函數的參數類型;
函數若是被設計爲遞歸函數(在函數體中調用它自身)則函數的返回類型就不能被省略,即遞歸函數沒法推斷函數的返回類型;
函數體實際上也被稱之爲函數塊,一個塊中若是隻有一條語句則能夠省略塊兩端的大括號,如:def max2(x: Int, y: Int) = if (x > y) x else yapp

//函數的調用與表達式的調用相似,以下:
scala> def max2(x: Int, y: Int) = if (x > y) x else y
max2: (x: Int, y: Int)Int
scala> max2(3,5)
res4: Int = 5
//函數也能夠被推斷爲Unit類型:
scala> def greet()=println("Hello, world!")
greet: ()Unit
//下面的函數定義返回Int類型,可是實際上函數被推斷爲不返回任何值,即Unit類型,
scala> def greet():Int=println("Hello, world!")
<console>:11: error: type mismatch; //實際返回的類型與定義的返回類型不匹配
found : Unit //實際的返回類型
required: Int //定義的返回類型
def greet():Int=println("Hello, world!")

E、Scala腳本編寫與調用

#編寫Scala腳本:編程語言

[root@CloudDeskTop install]# vi test.scala
[root@CloudDeskTop install]# cat test.scala
//使用args數組接收傳入腳本的參數
println("Hello:"+args(0))
println("Hello:"+args(1))
[root@CloudDeskTop install]# scala test.scala liming zhangsan
Hello:liming
Hello:zhangsan

說明:
scala腳本(test.scala)中可使用args數組來得到傳入腳本(test.scala)的參數,注意取參數所用的是小括號,不是中括號;scala腳本中的註釋與Java中的註釋是相同的,使用雙斜槓標記單行註釋,使用/*......*/標記多行註釋。

F、while循環

F一、Scala中沒有++i、--i、i++、i--的運算模式,可使用i=i+一、i+=1來予以代替
F二、Scala中默認一行一條語句,若是須要在同一行放置多條語句則應該使用英文分號隔開
F三、Scala與Java相同,if、switch、while、for等後面的條件表達式都須要使用小括號括起來,這與Python、Ruby是不一樣的

F、for循環

scala> val list=List("zhu","ge","liang")
list: List[String] = List(zhu, ge, liang)

scala> for(ele<-list) println(ele)
zhu
ge
liang
//說明:因爲for循環體中就只有一條語句(println(arg))因此省略了大括號

for表達式中<-後面的參數是一個集合,前面的參數是一個迭代變量,該迭代變量是隱式的val聲明常量,在循環塊中不能改變它的值,可是每次迭代都將從新定義和初始化它的值

scala> for(ele<-list){ele="sdnj";println(ele)} //試圖在循環體中對它賦值是錯誤的
<console>:13: error: reassignment to val //由於它被指定爲常量,儘管如此,你不能顯式的寫成for(val ele<-list){println(ele)},這是語法規定所需
for(ele<-list){ele="sdnj";println(ele)}

G、函數式編程(函數自己做爲參數傳遞)

foreach迭代函數
foreach函數的參數接收一個函數對象,函數對象的=>符號左邊是參數列表,右邊是函數體,參數arg的類型沒有指定則經過Scala來自動推斷,而函數的返回類型沒有指定也是經過函數體的返回值來進行自動推斷,函數的參數函數是經過隱函數來定義的;

隱函數的特徵:
A、隱函數的定義中沒有關鍵字def和函數名
B、隱函數的參數類型並非必須的,它能夠經過實參值進行自動類型推斷,這是與顯函數定義不一樣的地方
C、隱函數的參數列表中若是隻有一個參數則沒有給定參數類型的狀況下其參數兩端的小括號能夠省略,甚至
能夠直接省略掉參數的定義和賦值符號,直接造成偏函數的定義
D、隱函數無需定義返回類型,返回類型根據函數體自動推斷
D、函數體的賦值符號是=>,而不是=

[root@CloudDeskTop install]# vi test.scala
[root@CloudDeskTop install]# cat test.scala 
args.foreach(arg=>println(arg))
[root@CloudDeskTop install]# scala test.scala zhu ge liang
zhu
ge
liang

小結:
全部變量、常量、函數在定義時其類型(對於函數而言是返回類型)是可選的(若是顯式的給定類型則給定類型將做爲自動化類型推斷結果的一種校驗),對於函數的參數類型分兩種狀況,在顯式定義一個命名函數時其參數類型不可省略,在函數式編程領域中其參數函數的參數類型則是可選的(一樣,若是顯式的給定類型則給定類型將做爲自動化類型推斷結果的一種校驗)

//若是須要顯式指定參數類型則須要使用小括號將參數列表括起來:
scala> val list=List("zhu","ge","liang")
list: List[String] = List(zhu, ge, liang)
scala> list.foreach((ele:String)=>println(ele))//注意foreach不能對ArrayList集合遍歷
zhu
ge
liang

//若是存在多個參數則函數定義格式以下:
(key:String,value:Object)=>println(key+":"+value)

小結:
在Scala中任何類型的變量在定義時都必須初始化(包括類),類在定義時使用類體初始化類的定義(但在Scala中官方並不認爲這被稱爲初始化,由於它沒有賦值符號),

函數在定義時使用函數體進行初始化,賦值符號是=(顯函數定義)或=>(隱函數定義),常量和變量在定義時使用常量值或變量值進行初始化,賦值符號是=

//若是隻有一個參數則能夠省略參數定義和箭頭部分(這種書寫方式被稱爲偏應用函數)
scala> list.foreach(println)
zhu
ge
liang

注意:實際上foreach函數是for循環的變體,本質上都是相同的迭代方式,for循環的可讀性更高,但foreach函數是標準的函數式編程寫法

H、數組

H一、通用方式建立數組和使用數組

//當沒有指定泛型參數時默認數組元素類型爲Nothing類型,與Any類型相反,Nothing表明全部類的子類型,這意味着任何類型的數據不通過強制下轉型將沒法放入數組中去

//小括號中的參數2表明數組的長度(即數組中元素的個數),Scala根據此參數初始化數組的長度,這與Java不一樣,Scala中初始化數組的長度、下標的訪問都是使用小括號,而不是方括號

scala> var arr=new Array(2);
arr: Array[Nothing] = Array(null, null)

scala> arr(0)="zhugeliang"
<console>:13: error: type mismatch;
found : String("zhugeliang")
required: Nothing
arr(0)="zhugeliang"
^

注意: 從上面實例能夠發現使用數組長度來初始化Scala數組時必須指定其泛型,不然數組中將沒法放入任何元素

//指定了泛型以後就能夠直接放入元素了
scala> var arr=new Array[String](3);
//若是須要顯式指定變量類型能夠像下面這樣定義,能夠看到泛型其實是類型的一部分
scala> var arr:Array[String]=new Array[String](3);
arr: Array[String] = Array(null, null, null)

scala> arr(0)="mmzs"
scala> arr(0)
res1: String = mmzs
scala> arr(1)="淼淼之森"
scala> arr(2)="mmzsblog"

//foreach並傳遞隱函數遍歷
scala> arr.foreach(ele=>println(ele))
mmzs
淼淼之森
mmzsblog

//foreach並傳遞偏函數遍歷
scala> arr.foreach(println)
mmzs
淼淼之森
mmzsblog

//使用for循環遍歷
scala> for(ele<-arr)println(ele)
mmzs
淼淼之森
mmzsblog

//使用for循環並構建下標集合遍歷,to關鍵字其實是一個帶一個Int參數的方法,0 to 2被解釋成(0).to(2),to方法返回的是一個序列,arr.length描述集合的長度
scala> for(i<-0 to arr.length-1)println(arr(i))
mmzs
淼淼之森
mmzsblog

說明:
從技術上講,Scala中沒有操做符重載的概念,全部的操做符都將被視爲方法而後實現對方法的調用,這也是由於Scala中的數組實際上就是一個普通Scala類的實現而已,
對數組類長度和下標的訪問都是對該類中相應方法的調用,這也是下標的訪問爲何是小括號而不是方括號的緣由,好比對算術運算符+、-、*、/的訪問也是視爲方法來調用的:

scala> 1+2
res23: Int = 3
scala> 1.+(2)
res24: Int = 3
scala> (1).+(2)
res25: Int = 3

這個原則不只僅侷限於數組:任何對某些在括號中的參數的對象的應用將都被轉換爲對工廠方法apply(工廠方法apply是一個帶可變長度參數的方法)的調用。固然前提是這個類型實際定義過apply方法。
因此這是一個通則,上面對數組的讀寫過程實際上被解釋爲:

scala> var arr:Array[String]=new Array[String](3);
arr: Array[String] = Array(null, null, null)
scala> arr.update(0,"zhu")
scala> arr.update(1,"ge")
scala> arr.update(2,"liang")
scala> for(i<-0.to(2))println(arr.apply(i))
zhu
ge
liang

H二、簡潔方式建立數組和使用數組

//注意這種模式下不能再使用new關鍵字,同時也無需指定數組的泛型和長度,由於在建立數組的同時已經用實際的元素類型和值初始化了

scala> val arr=Array("zhu","ge","liang")
arr: Array[String] = Array(zhu, ge, liang)

scala> arr.apply(0)
res8: String = zhu
scala> arr.apply(1)
res9: String = ge

//也能夠直接使用apply方法來建立數組(這種調用是直接對底層工廠方法的調用,效率或許更高,可是代碼表現得有點囉嗦)

scala> val arr=Array.apply("zhuzhu","gege","liangliang")
arr: Array[String] = Array(zhuzhu, gege, liangliang)

scala> arr.apply(1)
res10: String = gege

scala> arr(1)
res11: String = gege
//因爲數組元素的類型所有都是些基本類型,因而數組元素的類型被推斷爲AnyVal類型
scala> val arr=Array.apply(36,1.67,'A',true)
arr: Array[AnyVal] = Array(36, 1.67, A, true)

//因爲數組元素的類型所有都是些引用類型,因而數組元素的類型被推斷爲Object類型,在Java平臺上,AnyRef是java.lang.Object類的別名,在.Net平臺上,AnyRef是system.Object類的別名
scala> class User{}
defined class User

scala> val arr=Array.apply("zhugeliang",new User())
arr: Array[Object] = Array(zhugeliang, User@c9cd85d)

//因爲初始化指定的類型既有引用類型又有基本類型,因此數組元素的類型被推斷爲Any類型
scala> val arr=Array.apply("liubei",39,1.77)
arr: Array[Any] = Array(liubei, 39, 1.77)

//使用簡潔方式建立數組時最好不要加泛型,這樣可使得Scala完成自動泛型推斷,若是自定義了泛型則要求數組中的元素所有與泛型兼容,不然將拋出類型不匹配的異常
scala> val arr=Array[String]("ligang",23)
<console>:11: error: type mismatch;
found : Int(23)
required: String
val arr=Array[String]("ligang",23)
^

小結:
使用new關鍵字建立數組時,小括號中的參數是惟一的,且是必選參數,並且必須是一個表明數組長度的整型數據,使用簡潔方式建立數組時小括號中的參數是0到多個可選的參數值,這些數據是數組中的元素值,因爲建立數組時沒有指定泛型則默認泛型爲Nothing類型,因此對於泛型而言有如下建議:
  a、若是使用new方式建立數組則必須指定泛型,不然後續沒法爲Nothing類型的數組元素賦值,使用new方式建立數組適合於數組中元素較多沒法一次性枚舉出來的狀況使用
  b、若是使用簡潔方式建立數組則建議使用Scala的自動類型推斷,但你也能夠強制指定泛型,以保證初始化的枚舉值類型都是準確無誤的,使用簡潔方式建立數組適合於數組中元素較少能夠一次性枚舉出來的狀況使用

I、列表List

Scala中的List(全名是scala.List)不一樣於Java中的java.util.List類型,Scala中的List與字符串String的操做相似,它是一種徹底不可變的列表,任何對列表的增、刪、改操做都將產生一個新的列表對象返回,須要注意的是List與數組類型Array也不見得徹底相同,雖然他們的長度都是不能夠改變的,可是數組中的元素值則是能夠改變的,而List集合中的元素值不能被改變,一旦改變將產生新的列表對象
a、合併兩個列表並返回一個新的列表

//建立兩個列表,泛型根據初始化的元素類型自動推斷爲Any
scala> val myinfo=List("zhugeliang",39,1.77)
myinfo: List[Any] = List(zhugeliang, 39, 1.77)
scala> val youinfo=List("lingang",50,1.68)
youinfo: List[Any] = List(lingang, 50, 1.68)
//合併兩個列表中的元素(按順序合併)
scala> val info=myinfo:::youinfo
info: List[Any] = List(zhugeliang, 39, 1.77, lingang, 50, 1.68)
//合併後產生新的列表,地址再也不相同
scala> myinfo==info
res1: Boolean = false
scala> youinfo==info
res2: Boolean = false

b、在列表的首部插入數據,返回一個新的列表

scala> val list=List(68,86,99)
list: List[Int] = List(68, 86, 99)

scala> val list2=100::list
list2: List[Int] = List(100, 68, 86, 99)

scala> list==list2
res14: Boolean = false

說明:
不能使用new關鍵字實例化List對象,由於List.apply()方法被定義在scala.List伴生對象上;
以冒號結尾的方法名錶示調用關係上的反轉,即調用方法的對象是右邊的操做數,像上面的myinfo:::youinfo表示的調用關係是youinfo.:::(myinfo),而100::list表示的調用關係是list.::(100),如:

scala> list2.::(200)
res15: List[Int] = List(200, 100, 68, 86, 99)

scala> info.:::(myinfo)
res16: List[Any] = List(zhugeliang, 39, 1.77, zhugeliang, 39, 1.77, lingang, 50, 1.68)

而那些沒有以英文冒號結尾的關鍵字表示的方法名則調用方法的對象是左邊的操做數

c、串聯離散數據成列表對象

//使用Nil關鍵字能夠建立一個空列表
scala> Nil
res15: scala.collection.immutable.Nil.type = List()
scala> val list3="ligang"::27::1.67::Nil
list3: List[Any] = List(ligang, 27, 1.67)
//也可使用成員運算符調用方法,可是表現的很囉嗦
scala> val list4=Nil.::("liubei").::(36).::(1.67)
list4: List[Any] = List(1.67, 36, liubei)

d、列表元素訪問

//訪問列表中索引爲2的元素值
scala> list4(2)
res16: Any = liubei
//計算列表的尺寸,length屬性幾乎是全部集合所具有的屬性,它用於錶針集合的尺寸
scala> list4.length
res18: Int = 3
//返回列表的第一個元素或最後一個元素
scala> info.head
res19: Any = liubei
scala> info.last
res20: Any = 1.77
//列表是否爲空列表
scala> Nil.isEmpty
res21: Boolean = true
scala> info.isEmpty
res22: Boolean = false
//返回除去第一個元素後的列表
scala> List(10,20,30,40).tail
res28: List[Int] = List(20, 30, 40)
//返回除去最後一個元素後的列表
scala> List(10,20,30,40).init
res27: List[Int] = List(10, 20, 30)
//刪除左邊的兩個元素
scala> info
res43: List[String] = List(lingang, wangfang, changhua, zhangjin, guanyu)
scala> info.drop(2)
res46: List[String] = List(changhua, zhagjin, guanyu)
//刪除右邊的兩個元素
scala> info.dropRight(2)
res47: List[String] = List(lingang, wangfang, changhua)
//反轉元素列表
scala> List(10,20,30,40).reverse
res29: List[Int] = List(40, 30, 20, 10)
//轉換列表爲字符串
/*
mkString函數有兩次重載:
(sep: String)String 使用一個分隔符串接列表中的全部元素爲一個字符串
(start: String,sep: String,end: String)String 使用一個分隔符串接列表中的全部元素爲一個字符串,同時在這個字串的起始和結束位置追加第一個參數字串和最後一個參數字串
*/
scala> List(10,20,30,40).mkString(",")
res39: String = 10,20,30,40
scala> List(10,20,30,40).mkString("(","|",")")
res42: String = (10|20|30|40)

e、列表過濾處理:

scala> val info=List("lingang","wangfang","changhua","zhangjin","guanyu")
info: List[String] = List(lingang, wangfang, changhua, zhangjin, guanyu)
/*
e一、count函數原型是:(p: Any => Boolean)Int,將集合中每個元素放入隱函數計算,並返回集合中知足條件(參數函數返回true)的元素數量 
*/
//使用隱函數計算info集合中元素的字符數爲6的元素個數
scala> info.count(s=>6==s.length)
res26: Int = 1
//使用偏函數計算info集合中元素的字符數爲6的元素個數
scala> info.count(6==_.length)
res1: Int = 1

/*
e二、exists函數原型是:(p: Any => Boolean)Boolean,只要集合中有一個元素知足條件(參數函數返回true)則exists函數返回true
*/
//判斷集合info中是否存在元素的值爲changhua的元素
//使用隱函數計算
scala> info.exists(s=>s=="changhua")
res3: Boolean = true
scala> info.exists(s=>s=="changshad")
res4: Boolean = false
//使用偏函數計算
scala> info.exists(_=="changhua")
res6: Boolean = true

/*
e三、forall函數原型是:(p: Any => Boolean)Boolean,集合中全部元素知足條件(參數函數返回true)則exists函數返回true;
該函數與exists函數是互補的,exists函數是描述or的關係,而forall是描述and的關係
*/
//判斷集合info中的元素類型是否都是String類型
scala> info.forall(s=>s.getClass().getSimpleName()=="String")
res12: Boolean = true
scala> info.forall(_.getClass().getSimpleName()=="String")
res14: Boolean = true
scala> info.forall(s=>s.getClass().getSimpleName()=="Integer")
res13: Boolean = false
scala> List("lingang","chenghua").forall(_.getClass().getSimpleName()=="String")
res15: Boolean = true
scala> List("lingang","chenghua",50).forall(_.getClass().getSimpleName()=="String")
res16: Boolean = false
scala> List("lingang","chenghua").forall(_.getClass().getName=="java.lang.String")
res17: Boolean = true
scala> List("lingang","chenghua",100).forall(_.getClass().getName=="java.lang.String")
res19: Boolean = false

說明:
在Scala中比較字符串是否相同可使用雙等號,固然你使用equals方法來比較也是OK的:
scala> List("lingang","chenghua").forall(_.getClass().getName.equals("java.lang.String"))
res20: Boolean = true

/*
e四、filter函數原型是:(p: Any => Boolean)List[Any],過濾出知足條件(參數函數返回true)的全部元素並返回這些元素組成的子列表
*/
//過濾出字串長度爲6的全部元素組成的子列表
scala> info.filter(s=>s.length==6)
res7: List[String] = List(guanyu)
scala> info.filter(_.length==6)
res9: List[String] = List(guanyu)

/*
e五、map函數原型是:(f: Any => B)(implicit bf: scala.collection.generic.CanBuildFrom[List[Any],B,That])That,將集合中的每個元素使用map的參數函數處理並收集參數函數處理後的返回值組成的列表
*/
scala> List(10,20,30,40).map(s=>s+5)
res35: List[Int] = List(15, 25, 35, 45)
scala> List(10,20,30,40).map(_+5)
res37: List[Int] = List(15, 25, 35, 45)

/*
e六、foreach函數原型是:(f: Any => U)Unit,將集合中的每個元素放入參數函數中去並調用參數函數處理,參數函數的返回類型根據參數函數體自動推斷,foreach函數無返回值
*/
scala> info.foreach(s=>println(s))
lingang
wangfang
changhua
zhangjin
guanyu
scala> info.foreach(println(_))
lingang
wangfang
changhua
zhangjin
guanyu

J、元素Tuple

  元組與列表相同也是不可改變的,任何對元組的增、刪、改都將返回新的元組對象,元組與列表不一樣的是列表List中的類型都是相同的,使用列表時爲了可以在其中容納不一樣類型的元素,咱們不得不使用與這些元素兼容的超類型,如:AnyVal、AnyRef或Any類型等,可是元組Tuple中的元素類型能夠是不相同的,元組Tuple的實際類型取決於元組中元素的數量和各個元素的類型。
a、通用方式建立元組

//元組的泛型被自動推斷爲Tuple2[String,Int],下面的這條語句存在兩次類型推斷過程,首先是推斷右邊Tuple2的泛型爲Tuple2[String,Int],而後在推斷左邊info變量的類型爲Tuple2[String,Int]
//TupleX中的X表明元組中元素的數量,元組的泛型由元組中的各個元素類型來肯定,元組中的元素數量和類型決定了元組自身的類型
scala> val info=new Tuple2("liubei",28)
info: (String, Int) = (liubei,28)
//訪問元組的第一個元素
scala> info._1
res54: String = liubei
//訪問元組的第二個元素
scala> info._2
res55: Int = 28

說明:
  不能像訪問List中元素那樣去訪問元組中的元素,由於List的apply方法返回的類型都是同一類型,然而元組的各個元素的類型不見得徹底相同,訪問元組中的元素只能使用成員運算符(.),其中元素格式爲_N,N表明元素在元組中的下標

//顯式指定元組的泛型,可是左邊的info變量的類型須要Scala自動推斷
scala> val info=new Tuple2[String,Int]("ligang",28)
info: (String, Int) = (ligang,28)
//顯式指定變量的類型和元組的泛型
scala> val info:Tuple2[String,Int]=new Tuple2[String,Int]("ligang",28)
info: (String, Int) = (ligang,28)

b、簡潔方式建立元組(無new關鍵字)

scala> val info=Tuple2("ligang",28)
info: (String, Int) = (ligang,28)
//也能夠顯式指定泛型和變量的類型
scala> val info=Tuple2[String,Int]("ligang",28)
info: (String, Int) = (ligang,28)
scala> val info:Tuple2[String,Int]=Tuple2[String,Int]("ligang",28)
info: (String, Int) = (ligang,28)

c、最簡方式建立元組(無Tuple關鍵字)

//info變量自動被推斷爲:Tuple2[String,Int]類型
scala> val info=("ligang",28)
info: (String, Int) = (ligang,28)
//也能夠顯式爲變量指定類型
scala> val info:Tuple2[String,Int]=("ligang",28)
info: (String, Int) = (ligang,28)

小結:
  元組Tuple具備比列表List更高一個層級的不可變型,元組Tuple相對於列表List的優點就是它的元素類型能夠是不一樣的,然而元組Tuple的缺點是沒有像列表List那樣豐富的API操做,元組中的數據幾乎是固定不變的。

K、Set集合

  在Scala中,Set集合分爲可變集合和不可變集合,其中的可變集合與Java中的Set集合是類似的,Set在Scala中被定義爲一個Trait,它的具體實現是HashSet,HashSet仍然分爲可變的HashSet和不可變的HashSet,全部可變的集合放置於scala.collection.mutable包中,而全部不可變的集合則放置於scala.collection.immutable包中,Set集合中的+=運算符在可變與不可變的具體集合實現中有着不一樣的實現,在可變的Set集合中,該運算至關於append,即直接往當前集合中追加元素,而在不可變的Set集合中,該運算至關於+產生的合併運算,這將致使產生新的Set集合對象,同時將合併後的新Set集合對象賦值給左邊的變量;Set集合中的元素是自動去重的,即沒有重複的元素,這個特徵不一樣於Array和List;建立任何Set集合(包括HashSet集合)都只能使用簡潔模式,不能使用new的方式來建立,今後你會發現規避使用new來建立對象在Scala中是一種更好的通用選擇。

//建立一個Set集合,泛型被自動推斷爲Any類型,左邊的set變量被自動推斷爲Set[Any]類型
scala> val set=Set("ligang",28,1.67)
set: scala.collection.immutable.Set[Any] = Set(ligang, 28, 1.67)
//也能夠顯式指定泛型和變量類型
scala> val set=Set[Any]("ligang",28,1.67)
set: scala.collection.immutable.Set[Any] = Set(ligang, 28, 1.67)
//追加一個元素到Set集合將返回一個新的Set集合對象
scala> val set02=set+"chenggang"
set02: scala.collection.immutable.Set[Any] = Set(ligang, 28, 1.67, chenggang)
scala> set==set02
res3: Boolean = false
//若是你但願將產生的新的Set集合對象再賦值回原來的變量,相似於字符串同樣的去改變原有變量,可使用+=運算符,因爲須要改變原有變量的引用值,因此須要使用var來定義該變量,而不是val
scala> var set=Set("ligang",28,1.67)
set: scala.collection.immutable.Set[Any] = Set(ligang, 28, 1.67)
//下面的這步操做至關於:set=set+"chenggang",這顯然是改變了原有set變量的值,這也是上面爲何要使用var來定義它的緣由所在
scala> set+="chenglong"
scala> set
res5: scala.collection.immutable.Set[Any] = Set(ligang, 28, 1.67, chenglong)
//再次追加相同的元素則不會追加成功
scala> set+="chenglong"
scala> set
res3: scala.collection.immutable.Set[Any] = Set(ligang, 28, 1.67, chenglong)

說明:
上面的操做也許會考慮到使用val從新定義set變量(而堅持不使用var),但這種狀況會發生遞歸錯誤,因此咱們只能使用另外一個變量set02來替換,或者使用var定義它而後使用+=運算符

scala> val set=set+"zhangsan"
<console>:12: error: recursive value set needs type
val set=set+"zhangsan"
^
從上面的Set集合建立過程能夠看出Set集合默認建立爲不可變的集合類型,若是你須要的是可變的集合類型則必須使用import顯式的導入可變類型的Set
scala> import scala.collection.mutable.Set
import scala.collection.mutable.Set
scala> val set=Set("ligang",28,1.67)
set: scala.collection.mutable.Set[Any] = Set(ligang, 1.67, 28)
//下面這句至關於append操做,直接改變集合對象自己,並不會產生新的集合對象
scala> set+="zhangsan"
res5: set.type = Set(ligang, 1.67, 28, zhangsan)
//再次追加相同的元素值則不會追加成功
scala> set+="zhangsan"
res6: set.type = Set(ligang, 1.67, 28, zhangsan)

/*
若是你想基於特定的實現類建立Set集合則必須使用import導入相應的類型,但實際生產上用的較少
*/
//導入可變的HashSet類型
scala> import scala.collection.mutable.HashSet
import scala.collection.mutable.HashSet
scala> val set=HashSet("ligang",28,1.67)
set: scala.collection.mutable.HashSet[Any] = Set(ligang, 1.67, 28)
//建立不可變的HashSet類型
scala> val set=scala.collection.immutable.HashSet("ligang",28,1.67)
set: scala.collection.immutable.HashSet[Any] = Set(28, ligang, 1.67)

Set小結:
對於不可變的Set集合類型變量應該使用var來進行定義以保證追加元素後產生的新集合對象可以被賦值回原來的變量,對於可變的Set集合類型一般是使用val來進行定義,此時追加元素將改變集合自己,而不會產生任何新的集合對象。

Array、List、Set、Tuple小結:
尺寸的可變性:
Array和Tuple是在實例化時定義長度的,實例化以後不能夠改變它的長度;而List、Set則能夠動態改變長度,如List能夠經過::追加元素產生新的List對象,而Set能夠經過+=追加元素產生新的Set對象或者直接改變集合自己;
集合中元素類型是否相同:
Array、List、Set集合中元素類型相同,Tuple集合中的元素類型能夠相同、也能夠不一樣;
集合中的元素值是否能夠改變:
Array集合中的元素值能夠改變,List和Tuple集合中的元素值不能被改變,Set集合中的元素有可變和不可變兩種實現(分別使用val和var來定義);
元素是否能夠重複:
Set集合中的元素不能夠重複,Array、List、Tuple集合中的元素值能夠重複;
泛型推斷原理:
對於不可變集合而言必須在實例化時指定各個元素的值,此時Scala能夠自動根據給定的元素值來推斷其集合的泛型;而對於可變集合則能夠延遲給定各個元素的值,此時的可變集合泛型在實例化時就會被自動推斷爲Nothing類型,此後須要添加到可變集合的各個元素不得不強制下轉型爲Nothing,不然將沒法添加元素到可變集合中,對於Array以前咱們就已經看到了,如今來看看可變集合Set,它將與Array遇到一樣的狀況:

scala> import scala.collection.mutable.Set
import scala.collection.mutable.Set

scala> val set=Set()
set: scala.collection.mutable.Set[Nothing] = Set()

scala> set+="ligang"
<console>:14: error: type mismatch;
 found   : String("ligang")
 required: Nothing
       set+="ligang"
            ^

L、Map集合

a、->與<-的區別:
前者是被定義在Any根類中的方法,即任何對象調用該方法都將返回一個二元素元組,該元素中的第一個元素是當前對象,第二個元素是參數對象

scala> "name"->"ligang"
res1: (String, String) = (name,ligang)
scala> "age"->28
res2: (String, Int) = (age,28)
scala> "height"->1.64
res3: (String, Double) = (height,1.64)
scala> 100->"zhanghua"
res4: (Int, String) = (100,zhanghua)
//也可使用成員運算符來調用該方法
scala> 150.->("zhanghua")
res5: (Int, String) = (150,zhanghua)

後者是被用在for循環中遍歷集合之用:

scala> val info=List(20,60,80)
info: List[Int] = List(20, 60, 80)
scala> for(e<-info)println(e)
20
60
80

b、建立不可變的Map對象
Map集合中下標被稱之爲Key,元素值被稱之爲Value,Map集合中的每個元素被稱之爲一個鍵值對的對象,這個鍵值對是一個包含了Key和Value的二元素元組

//首先建立三個鍵值對元組對象,它們是entry一、entry2和entry3
scala> val entry1="name"->"ligang"
entry1: (String, String) = (name,ligang)
scala> val entry2="age"->36
entry2: (String, Int) = (age,36)
scala> val entry3="height"->1.67
entry3: (String, Double) = (height,1.67)
//再建立不可變的Map對象,注意對不可變的Map應該使用var來定義,不然後續沒法使用+=運算符追加鍵值對
scala> var info=Map(entry1,entry2,entry3)
info: scala.collection.immutable.Map[String,Any] = Map(name -> ligang, age -> 36, height -> 1.67)
//訪問Map集合中的元素應根據Key來訪問Value
scala> info("name")
res8: Any = ligang
scala> info("age")
res9: Any = 36
//追加鍵值對
val entry3="height"->1.67
scala> val info2=info+entry4
info2: scala.collection.immutable.Map[String,Any] = Map(name -> ligang, age -> 36, height -> 1.67, weight -> 118)
scala> info==info2
res13: Boolean = false
//也可使用+=來追加鍵值對
scala> val entry5="birthday"->java.sql.Date.valueOf("1982-12-26")
entry5: (String, java.sql.Date) = (birthday,1982-12-26)
scala> info+=entry5
scala> info
res15: scala.collection.immutable.Map[String,Any] = Map(name -> liyongfu, age -> 36, height -> 1.67, birthday -> 1992-12-26)

c、建立可變的Map對象

scala> import scala.collection.mutable.Map
import scala.collection.mutable.Map
//注意對可變的Map應該使用val來定義,不然後續沒法使用+=運算符追加鍵值對
scala> val info=Map(entry1,entry2,entry3) info: scala.collection.mutable.Map[String,Any] = Map(age -> 36, name -> ligang, height -> 1.67) scala> info+=entry5 res16: info.type = Map(birthday -> 1992-12-26, age -> 36, name -> ligang, height -> 1.67) scala> info res17: scala.collection.mutable.Map[String,Any] = Map(birthday -> 1992-12-26, age -> 36, name -> ligang, height -> 1.67)

說明:
Scala中的集合類型默認引用的是不可變的集合類型,若是須要使用可變的集合類型則須要手動使用import導入scala.collection.mutable._(這裏的下劃線至關於java中的*),如:

scala> import scala.collection.mutable._
import scala.collection.mutable._
scala> val info=Map[String,Any]()
info: scala.collection.mutable.Map[String,Any] = Map()
//直接追加鍵值對
scala> info+="name"->"ligang"
res0: info.type = Map(name -> ligang)
scala> info+="age"->28
res1: info.type = Map(age -> 28, name -> ligang)

在Java中一般建立的集合對象都是可變的,同時若是引用集合對象的變量沒有使用final修改則該變量也是可變的,若是在Scala中須要像Java中的那種集合建立方式則應該是以下狀況:

scala> import scala.collection.mutable._
import scala.collection.mutable._
scala> var info=Map[String,Any]()
info: scala.collection.mutable.Map[String,Any] = Map()

M、函數式風格編程與文件操做

M一、var與val的選擇

  一般狀況下,若是使用var定義來實現編程,那麼這種風格就是Scala中的指令式風格,指令式風格對於C/C++以及Java程序員都是司空見慣的一種模式,若是須要向函數式風格化推動,則應該儘量的使用val編程,而再也不是使用var來編程;其二,一般咱們在編程中應該首先思考的是Scala的API,當咱們考慮到有難度時再回退到Java的API中來實現,這是一種不錯的思路。

M二、文件操做

//構建測試文件

[root@CloudDeskTop install]# vi testfile
[root@CloudDeskTop install]# cat testfile 
01    lingang    2009-12-28
02    zhanghua    1998-10-12
03    chengqiang    1923-11-18
04    歡迎來到mmzs
05    以爲有用的話
06    點個讚唄

//編寫腳本

[root@CloudDeskTop install]# vi testreadfile
[root@CloudDeskTop install]# cat testreadfile 
import scala.io._
if(args.length<=0){
println("args number is error...")
java.lang.System.exit(1)
}
val fileName=args(0)
val source:BufferedSource=Source.fromFile(fileName)
val its:Iterator[String]=source.getLines
for(line<-its) println(line.length+"=>"+line)

//調用腳本讀取文件內容並打印到控制檯

[root@CloudDeskTop install]# scala testreadfile testfile
27=>01    lingang    2009-12-28
28=>02    zhanghua    1998-10-12
30=>03    chengqiang    1923-11-18
14=>04    歡迎來到mmzs
12=>05    以爲有用的話
10=>06    點個讚唄

說明:
val its:Iterator[String]=source.getLines返回的是一個迭代器,迭代器指針指向磁盤文件的第一行,每循環一次都將從磁盤上讀取下一行的數據到內存中;
若是須要一次性將磁盤文件中的內容讀取到內存可使用迭代器調用toList方法:
val its:Iterator[String]=source.getLines
val allLines:List[String]=its.toList

//代碼以下
[root@CloudDeskTop install]# cat testreadfile 
import scala.io._
if(args.length<=0){
    println("args number is error...")
    java.lang.System.exit(1)
}
val fileName=args(0)
val source:BufferedSource=Source.fromFile(fileName)
val its:Iterator[String]=source.getLines
//for(line<-its) println(line.length+"=>"+line)
//今後行開始修改 val allLines:List[String]=its.toList println(allLines.length+"=>"+allLines) //結果以下 [root@CloudDeskTop install]# scala testreadfile testfile 6=>List(01 lingang 2009-12-28, 02 zhanghua 1998-10-12, 03 chengqiang 1923-11-18, 04 歡迎來到mmzs, 05 以爲有用的話, 06 點個讚唄)

 

相關文章
相關標籤/搜索