初識Scala

scala
介紹
1.什麼是Scala
Scala是一門現代的多範式語言,志在以簡潔、優雅及類型安全的方式來表達經常使用的編程模型。它平滑地集成了面向對象和函數式語言的特性。java

2.Scala是面向對象編程語言
鑑於一切值都是對象,能夠說Scala是一門純面向對象的語言。對象的類型和行爲是由類和特質來描述的。類能夠由子類化和一種靈活的、基於mixin的組合機制(它可做爲多重繼承的簡單替代方案)來擴展。git

3.Scala是函數式編程語言
鑑於一切函數都是值,又能夠說Scala是一門函數式語言。Scala爲定義匿名函數提供了輕量級的語法,支持高階函數,容許函數嵌套及柯里化。Scala的樣例類和內置支持的模式匹配代數模型在許多函數式編程語言中都被使用。對於那些並不是類的成員函數,單例對象提供了便捷的方式去組織它們。es6

此外,經過對提取器的通常擴展,Scala的模式匹配概念使用了right-ignoring序列模式,天然地延伸到XML數據的處理。其中,for表達式對於構建查詢頗有用。這些特性使得Scala成爲開發web服務等程序的理想選擇。web


4.Scala是靜態類型的
Scala配備了一個擁有強大表達能力的類型系統,它能夠靜態地強制以安全、一致的方式使用抽象。典型來講,這個類型系統支持:
泛型類
型變註解
上、下 類型邊界
做爲對象成員的內部類和抽象類型
複合類型
顯式類型的自我引用
隱式參數和隱式轉化
多態方法
類型推斷讓用戶不須要標明額外的類型信息。這些特性結合起來爲安全可重用的編程抽象以及類型安全的擴展提供了強大的基礎。express

5.Scala是可擴展的
在實踐中,特定領域應用的發展每每須要特定領域的語言擴展。Scala提供了一種語言機制的獨特組合方式,使得能夠方便地以庫的形式添加新的語言結構。
不少場景下,這些擴展能夠不經過相似宏(macros)的元編程工具完成。例如:編程

隱式類容許給已有的類型添加擴展方法。
字符串插值可讓用戶使用自定義的插值器進行擴展。api

6.Scala互操做
Scala設計的目標是與流行的Java運行環境(JRE)進行良好的互操做,特別是與主流的面向對象編程語言——Java的互操做盡量的平滑。Java的最新特性如函數接口(SAMs)、lambda表達式、註解及泛型類 在Scala中都有相似的實現。數組

另外有些Java中並無的特性,如缺省參數值和帶名字的參數等,也是儘量地向Java靠攏。Scala擁有相似Java的編譯模型(獨立編譯、動態類加載),且容許使用已有的成千上萬的高質量類庫。緩存

 


1 變量/不變量聲明與定義
值與變量的聲明
var/val x:T = e安全

variable 變量
value 值 不變量

 

val 不變量聲明(常量,相似java中final修飾的變量)
var 變量聲明

i,scala自動類型推斷,即聲明值時能夠不聲明類型,scala自動識別類型

ii,scala中變量/不變量 必須初始化(賦值),不能先聲明後賦值

iii, 爲了符合ii的要求,在沒有邏輯值使用的狀況下,
可以使用 _ 對於變量/不變量進行賦值
表明默認值(參考java屬性默認值)

iv, 聲明能夠連續聲明,
val x1,x2,x3 = 10
等價於
val x1 = 10
val x2 = 10
val x3 = 10
var同上

v,在REPL中,全部裸值和運算結果都會用resX 接收以做爲以後使用
resX是 val聲明的

vi,在scala中 val是更推薦的一種變量類型


2 方法聲明 與 函數聲明
def methodName(param:T,...):R={
return R;
}

i,參數的類型必須聲明,能夠爲參數提供默認值
def show(msg:String = "")=print(msg)

ii,若是沒有返回值能夠不寫返回類型

iii,若是有返回值,能夠省略return,代碼塊中最後一行必須產生返回值且類型要匹配

iv,Unit表明無返回值,scala中沒有void
:Unit能夠省略

v, 沒有返回值的方法 能夠省略 = ,此寫法被稱爲 過程

vi,不建議聲明過程,建議方法聲明長期添加 =

vii, 方法有返回值類型,返回類型也能夠省略,代碼塊最後一行
做爲返回值,且scala會作類型推斷,將最後一行結果類
型,當作方法返回值類型

viii,遞歸方法必須聲明返回值類型
def fac(i:Int):Int={
if(i > 0) i*fac(i-1) else 1
}

ix, 若是方法沒有參數,能夠省略小括號,此時
要注意調用方式,聲明時帶有小括號的方法,調用時能夠有小括號
也能夠沒有小括號
對於無小括號的方法,調用時必須不帶小括號

x,若是方法體中只有一行代碼,則能夠省略{}

函數聲明
能夠用變量接收的方法
函數是帶參數的表達式。

1.能夠定義一個匿名函數(即無名稱),返回給定的整數加一的結果:
(x:Int)=>x+1

=>的左邊是參數列表,右邊是一個包含參數的表達式。
2.帶名字的函數:
val addOne=(x:Int)=>x+1
println(addOne(1))//2

3.多個參數的函數
val add=(x:Int,y:Int)=>x+y
println(add(1,2))//3

4.無參數的函數
val getTheAnswer=()=>42
println(getTheAnswer())//42

 


3 類的聲明
Scala中的類是用於建立對象的藍圖,其中包含了方法、常量、變量、類型、對象、特質、類,這些統稱爲成員。類型、對象和特質將在後面的文章中介紹。

class 類名 private[package/this] (主構造器參數列表) extends 類/特質 with 特質1 with 特質2{}

class name(param:T,....){

}

i,類名後面的參數列表表明構造器的參數列表
class Student{
def show=print("hello")
}
var stu = new Student


ii,類名後面聲明的構造器稱爲主構造器,
class Student(name:String){
def show=print("hello"+name)
}

類中聲明的構造器稱爲輔助構造器
1. 輔助構造器的名稱爲def this
2. 每一個輔助構造器都必須以一個對先前已定義的其餘輔助構造器或主構造器的調用開始

class Student {
private var name = " "
private var age = 0

def this(name: String){ //輔助構造器1
this() //調用主構造器
this.name = name
}
def this(name: String,age: Int){ //輔助構造器2
this(name) //調用前一個輔助構造器
this.age = age
}
}


iii,私有構造器
class Student private(name:String)

iv,主構造器的參數,若是在類內的方法中使用過,則升格成字段/屬性
class Student(name:String){
def show=print("hello"+name)
}

v,主構造器參數,
若是用var修飾,則升格成字段/屬性並默認提供get/set函數
若是用val修飾,則升格成字段/屬性並默認提供get函數
get函數名爲 字段名
set函數名爲 字段名_=

class Student(var name:String){
def show=print("hello"+name)
}
object Student extends App {
var s = new Student("zhangsan");
s.name_=("lisi")
print(s.name)
}


@BeanProperty 可讓生成的字節碼文件中提供 java中的set方法,而且調用 字段名_= 時候轉化成調用set字段名

class Student(@BeanProperty var name:String){
def show=print("hello"+name)
}
object Student extends App {
var s = new Student("zhangsan");
s.name="lisi" //等於調用了setName
print(s.name)
}

vi,主構造器 參數 帶private var/val,則提供私有的get/set

vii,類中能夠聲明屬性 和 函數,scala中沒有static修飾符
類中的函數都是非靜態函數

樣例類
Scala有一種特殊的類叫作樣例類(case class)。
默認狀況下,樣例類通常用於不可變對象,而且可做值比較。
你可使用case class關鍵字來定義樣例類。
case class Point(x: Int, y: Int)

1.實現了apply方法,意味着你不須要使用new關鍵字就能建立該類對象
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)

2.它們的值能夠進行比較。
if (point == anotherPoint) {
println(point + " and " + anotherPoint + " are the same.")
} else {
println(point + " and " + anotherPoint + " are different.")
} // Point(1,2) and Point(1,2) are the same.

if (point == yetAnotherPoint) {
println(point + " and " + yetAnotherPoint + " are the same.")
} else {
println(point + " and " + yetAnotherPoint + " are different.")
} // Point(1,2) and Point(2,2) are different.

//具體緣由以後討論

3.實現了類構造參數的getter方法(構造參數默認被聲明爲val),可是當你構造參數是聲明爲var類型的,它將幫你實現setter和getter方法

 


4 對象的聲明

object name{

}

i,scala中沒有static,故想表示static的含義,利用對象表示
對象中的函數默認都是靜態函數,用對象名直接調用

object Test{
def show=println(hello)
}
Test.show

ii,擁有同名class的object稱爲該class的伴生對象,在同一個源文件中的話,能夠利用伴生對象訪問class的私有屬性

class Student(@BeanProperty private var name:String){
def show=print("hello"+name)
}
object Student extends App {
var s = new Student("zhangsan");
s.name="lisi" //等於調用了setName
print(s.name)
}


iii, apply方法的使用,一般狀況下,咱們會在伴生對象中定義一個apply方法,來產生該類的實例,scala容許語法簡化成對象名() 參考scala api

class Student(name:String){
def show=print("hello"+name)
}
object Student{
def apply(name: String): Student = new Student(name)
def main(args:Array[String]){
var s = Student("zhangsan");
}
}


特質
特質 (Traits) 用於在類 (Class)之間共享程序接口 (Interface)和字段 (Fields)。 它們相似於Java 8的接口。 類和對象 (Objects)能夠擴展特質,可是特質不能被實例化,所以特質沒有參數。

1定義特質:
格式: trait 特質名 extends 類/特質 with 特質1 {}
總結:
1.能夠包含具體方法/屬性
2.能夠包含抽象方法/屬性
3.特質 能夠 混入 類/對象/特質/實例(對象)
案例:
例1:最簡化的特質就是關鍵字trait+標識符:
trait HairColor
例2:特徵做爲泛型類型和抽象方法很是有用。
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
擴展 trait Iterator [A] 須要一個類型 A 和實現方法hasNext和next。
2使用特質:
使用 extends 關鍵字來擴展特徵。而後使用 override
關鍵字來實現trait裏面的任何抽象成員:
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}

class IntIterator(to: Int) extends Iterator[Int] {
private var current = 0
override def hasNext: Boolean = current < to
override def next(): Int = {
if (hasNext) {
val t = current
current += 1
t
} else 0
}
}

val iterator = new IntIterator(10)
iterator.next() // returns 0
iterator.next() // returns 1
這個類 IntIterator 將參數 to 做爲上限。它擴展了 Iterator [Int],這意味着方法 next 必須返回一個Int。

override 能夠重寫父類中的字段和方法

 

3子類型:
凡是須要特質的地方,均可以由該特質的子類型來替換。
import scala.collection.mutable.ArrayBuffer

trait Pet {
val name: String
}

class Cat(val name: String) extends Pet
class Dog(val name: String) extends Pet

val dog = new Dog("Harry")
val cat = new Cat("Sally")

val animals = ArrayBuffer.empty[Pet]
animals.append(dog)
animals.append(cat)
animals.foreach(pet => println(pet.name)) // Prints Harry Sally
在這裏 trait Pet 有一個抽象字段 name ,name 由Cat和Dog的構造函數中實現。最後一行,咱們能調用pet.name的前提是它必須在特質Pet的子類型中獲得了實現。

4經過混入(MIXIN)來組合類
當某個特質被用於組合類時,被稱爲混入。
abstract class A {
val message: String
}
class B extends A {
val message = "I'm an instance of class B"
}
trait C extends A {
def loudMessage = message.toUpperCase()
}
class D extends B with C

val d = new D
println(d.message) // I'm an instance of class B
println(d.loudMessage) // I'M AN INSTANCE OF CLASS B

類D有一個父類B和一個混入C。一個類只能有一個父類可是能夠有多個混入(分別使用關鍵字extend和with)。混入和某個父類可能有相同的父類。


5 類型聲明
type A = Int
當類名過長,或者有重複時進行使用,減小代碼長度

scala自己沒有定義String類型,利用type 引用java.lang.String
查看Predef類


6 scala標示符與命名
變量 類名 對象名 函數 標示符

以字母或下劃線開頭,後面能夠有更多的字母,數字或下劃線。 $字符是Scala中的保留關鍵字,不該在標識符中使用。

如下是合法的字母數字標識符
age, salary, _value, __1_value
如下是非法標識符
$salary, 123abc, -salary

反引號能夠包圍特殊標示符
var `return` = 10
var return = 10

 

7 scala中的關鍵字
implicit
Scala 2.10引入了一種叫作隱式類的新特性。隱式類指的是用implicit關鍵字修飾的類。在對應的做用域內,帶有這個關鍵字的類的主構造函數可用於隱式轉換。

例如,定義函數
def show(msg:String)=println(msg)
此時 調用show必須傳參String,若是傳參Int則報錯
能夠用implicit def幫助咱們在必定代碼範圍內將
Int 轉化成 String

object Student{
def show(msg:String)=print(msg)
def main(args: Array[String]): Unit = {
implicit def intToString(i:Int)=i.toString
show("hello")
show(300)
}
}

i,隱式參數
當咱們在定義方法時,能夠把最後一個參數列表標記爲implicit
表示該組參數是隱式參數。一個方法只會有一個隱式參數列表,
置於方法的最後一個參數列表。若是方法有多個隱式參數,
只需一個implicit修飾便可。 當調用包含隱式參數的方法是
,若是當前上下文中有合適的隱式值,則編譯器會自動爲
改組參數填充合適的值。若是沒有編譯器會拋出異常。
固然,標記爲隱式參數的咱們也能夠手動爲該參數添加默認值。

scala > def calcTax(amount: Float)(implicit rate: Float): Float = amount * rate
scala > implicit val currentTaxRate = 0.08F
scala > val tax = calcTax(50000F) // 4000.0

ii,隱式轉換類型 (隱式函數,隱式類)
使用隱含轉換將變量轉換成預期的類型是編譯器最早使用
implicit 的地方。這個規則很是簡單,
當編譯器看到類型X而卻須要類型Y,它就在當前做用域
查找是否認義了從類型X到類型Y的隱式定義

iii,隱式調用函數
隱式調用函數能夠轉換調用方法的對象,
好比編譯器看到X .method,而類型 X
沒有定義 method(包括基類)方法,那麼編譯器就查找
做用域內定義的從 X 到其它對象的類型轉換,
好比 Y,而類型Y定義了 method 方法,
編譯器就首先使用隱含類型轉換把 X
轉換成 Y,而後調用 Y 的 method。

查看Int api中的隱式函數

 

8 數據類型 純粹面向對象的

val i:Int = 10;

Byte Short Int Long
Double Float
Char Boolean
以上類型爲scala的基本數據類型,且爲scala自定義類型

i,這些類型中的全部操做符都是方法,如 + - * /
由此能夠推導,scala中調用無參數的方法形式
10+20 即 10.+(20)
s.show("hello") 即 s show "hello"

ii,這些類型都隱式轉化成了RichXXX,用來豐富功能

String 自己使用的就是java.lang.String,
會隱式轉化成StringOps

統一類型
在Scala中,全部的值都有類型,包括數值和函數。下圖闡述了類型層次結構的一個子集。
Any (頂級類型)
AnyVal AnyRef(java.lang.Object)
^ List
| Option
Double YourClass
Dloat ^
Long |
Int |
Short |
Byte |
Boolean |
Char Null
Unit ^
^ |
| |
Nothing(底部類型)

1Scala類型層級
Any是全部類型的超類型,也稱爲頂級類型。它定義了一些通用的方法如equals、hashCode和toString。Any有兩個直接子類:AnyVal和AnyRef。

AnyVal表明值類型。有9個預約義的非空的值類型分別是:Double、Float、Long、Int、Short、Byte、Char、Unit和Boolean。Unit是不帶任何意義的值類型,它僅有一個實例能夠像這樣聲明:()。全部的函數必須有返回,因此說有時候Unit也是有用的返回類型。

AnyRef表明引用類型。全部非值類型都被定義爲引用類型。在Scala中,每一個用戶自定義的類型都是AnyRef的子類型。若是Scala被應用在Java的運行環境中,AnyRef至關於java.lang.Object。

值類的空間是平坦的;全部的值類都是scala.AnyVal的子類型,可是它們不是其餘類的子類。可是不一樣的值類類型之間能夠隱式地互相轉換。例如,須要的時候,類scala.Int的實例能夠經過隱式轉換放寬到類scala.Long的實例;Int支持min、max、until、to、abs等操做,實際上是從類Int隱式轉換到scala.runtime.RichInt的。

AnyRef是引用類型。全部非值類型都定義爲引用類型.它實際上是Java平臺上java.lang.Object類的別名。所以Java裏寫的類和Scala裏寫的都繼承自AnyRef。

Scala類與Java類的不一樣在於它們還繼承自一個名爲ScalaObject的特別記號特質。是想要經過ScalaObject包含的Scala編譯器定義和實現的方法讓Scala程序的執行更高效。
類型轉化.

下面是一個示例,說明了字符串、整型、布爾值和函數都是對象,這一點和其餘對象同樣:

val list: List[Any] = List(
"a string",
732, // an integer
'c', // a character
true, // a boolean value
() => "an anonymous function returning a string"
)

list.foreach(element => println(element))

2類型轉化
值類型能夠按照下面的方向進行轉換:
Byte->Short->Int->Long->Float->Double
^
|
Char
例1:
val x: Long = 987654321
val y: Float = x // 9.8765434E8 (note that some precision is lost in this case)

val face: Char = '☺'
val number: Int = face // 9786
例2:轉換是單向,下面這樣寫將不會經過編譯。
val x: Long = 987654321
val y: Float = x // 9.8765434E8
val z: Long = y // Does not conform

3Nothing和Null
scala.Null和scala.Nothing是用統一的方式處理Scala面向對象類型系統的某些"邊界狀況"的特殊類型。
Nothing是全部類型的子類型,也稱爲底層類型。沒有一個值是Nothing類型的。它的用途之一是給出非正常終止的信號,如拋出異常、程序退出或者一個無限循環(能夠理解爲它是一個不對值進行定義的表達式的類型,或者是一個不能正常返回的方法)。

Null是全部引用類型的子類型(即AnyRef的任意子類型)。它有一個單例值由關鍵字null所定義。Null主要是使得Scala知足和其餘JVM語言的互操做性,可是幾乎不該該在Scala代碼中使用。咱們將在後面的章節中介紹null的替代方案。

例1:
def error(message: String): Nothing = throw new RuntimeException(message)
例2:
def divide(x: Int, y: Int): Int = if(y != 0) x / y else error("Can't divide by zero")


9 應用程序對象

object XXX{
def main(args:Array[String]){

}
}

object XXX extends App{

}

 

 

============================各類表達式=====================================

 


10 if表達式
if (boolean expression) value else value

i,scala是面向表達式的語言,全部東西都是表達式,而且有值
故 if表達式會返回值

ii,當if 值的類型 和 else 值的類型不同時,注意接收結果
的類型

var s:Any = if(1 == 1) "hello" else 0
var s:Any = if(1 == 1) "hello" else new Student


11 複合表達式
i,複合表達式是用括號括起來的零個或多個表達式的序列。

ii,複合表達式的結果是代碼塊中的最後一行表達式

val average = {
val n1 = readLine("Enter a number: ").toDouble
val n2 = readLine
("Enter another number:").toDouble
(n1 + n2) / 2
}

iii,當一個方法只接受一個參數(除了對象)時,能夠將該參數放在大括號內而不是小括號內
println {
var x = 2
while (x < 1000) x *= 2
x
}

val in = new FileInputStream("src/test")
var len = 0
while({len = in.read();
len != -1}){

}

Array(100,200,300).map{x => println(x); println("hello")}

12 輸入輸出
Console.readLine

Console.println 過期

scala.io.StdIn.readLine


=============================for推導+模式匹配======================
13 for循環和for推導式

for(i <- e) E(i)

i,for(i <- e)稱爲發生器,E(i)稱爲函數體

ii,e 能夠是各類集合,包括數組、列、表達式的等或有上下界的數據範圍
1 to 10 (1 <= i <=10)
1 until 10 (1 < i <=10)

 

iii,守衛 即在for中添加if
for(i <- e)if() E(i)

for (i <- 1 to 10) if(i%2 != 0){
println(i)
}

for (i <- 1 to 10 by 2) if(i%2 != 0){
println(i)
}

for(i <- e;if()) E(i)
for (i <- 1 to 10 if(i%2 != 0)){
println(i)
}

能夠添加多個守衛 分好隔開

for(i <- e;if();if()) E(i)
for (i <- 1 to 10;if(i%2 != 0);if(i%3!=0)){
println(i)
}

iv,嵌套循環
for(i <- e1)for(j <- e2)E(i,j)

for(i <- 1 to 5){
for(j <- 1 to i){
print("* ")
}
println()
}

for(i <- e1;j <- e2)E(i,j)

for(i <- 1 to 5;j <- 5 to 10){
println(i+" "+j)
}
* 可使用任意多的表達式來得到循環中使用的變量
for(i <- 1 to 5;from = 10 - i;j <- 5 to i){
println(i+" "+j)
}


v,嵌套循環能夠爲每一個發生器獨立添加守衛
for(i <- e1;if A;j <- e2;if B)E(i,j)

for(i <- 1 to 5;if i%2 != 0;j <- 5 to 10;if j%2 != 0 ){
println(i+" "+j)
}

vi,蒐集每次的循環的值,造成集合,帶有yield的for循環稱爲for推導式
for(i <- e) yield E(i)
val n = for(i <- 1 to 10) yield i%3

vii,yield保留字返回的類型跟for循環體第一個 <- 語句的集合類型相同,如非集合時
返回的是序列
var arr:Array[Boolean] = for(i <- Array(100,200,300)) yield i==i

viii, zipWithIndex能夠幫助咱們獲取元素的序號
var m = Array(20,30,40,50).zipWithIndex
for((x,y) <- m){
println(x+":"+y)
}


1.模式匹配
1.1 格式
express match{
case value1 => result1
case value2 => result2
case value3 => result3
........
}
1.2 match表達式相似於其餘語言的switch語句,提供多個備選項中進行選擇
a match{
case e1 => E1
case e2 => E2
....
}
eg:
val ch='+';
ch match{
case '-' => -1
case '+' => 1
}
若a匹配e1則執行E1,若a匹配e2則執行E2,以此類推
a能夠是數組、任意類型值等,en能夠是對應的值,常量,變量,甚至是類型
match表達式能用以直接賦值,如val sign=a match{case e1=> 123;case e2=> "123"}
匹配是從上而下的

1.3匹配語句case後接 _ 表明的是任意,通常在最後的case語句中這麼寫,即匹配不到上面的值時,執行
如 a match {
case e1 =>...
case e2 =>...
case _ =>....
}

匹配語句返回的值有多種類型時,Scala不能執行類型推斷,而且只會返回Any類型
如 val final=a match {
case e1 => "HI"
case e2 => 'H'
case e3 => 123
}
eg:
val sign ="+";
sign match{
case "-" => "---------"
case "+" => "1"
case _ => "is error"
}
1.4 case 能夠用來匹配 常量 變量 類型 IndexedSeq Option case class等
1.匹配常量
val num=10;
val one=1;
(num>5) match{
case true => num
case false => 5
}
num match{
case one => 1
case 2 => 2
case _ => 0
}
scala默認首字母大寫的字符串爲常量,首字母小寫的字符串爲變量,若是但願在模式匹配中用首字母小寫的常量須要用反引號 ` 進行標註.
scala> val ch = 3.14
scala> val mypi = 3.14
scala> val res = ch match {
| case `mypi` => true
| case _ => false
| }
res: Boolean = true
2.匹配變量
object match{
case x if x==null =>
//......
case x =>

}
3.類型匹配
eg:
val num:Any=32
num match{
case s:String => s.toInt
case x:Int => x
case _ => 0
}
eg:
def getType(a:Any){
a match{
case _ :Array[Char] => println("Array[Char]")
case _ :Int => println("Int")
case _ :Char => println("Char")
case _ => println(「Error")
}
}
注意:泛型的類型匹配要注意如List[String]、Map[Char,Int]等不會成功匹配,如 List[Int]等亦不可匹配,於是每每使用通配符List[ _ ]進行匹配,但Array[Int]是可行的
匹配發生在運行期,Java虛擬機中泛型的類型信息是被擦除的。所以,不能用類型匹配特定的Map類型。
case m:Map[String,Int] => //別這樣作!
能夠匹配一個通用的映射:
case m:Map[_,_] => //OK
可是對於數組而言,元素的類型信息是無缺的。你能夠匹配到Array[Int]

4.匹配數組,列表和元組
scala> def matchArr(x:Array[Int]):String =
| x match {
| case Array(0) => "Only 0" //僅含一個元素0的數字
| case Array(x,y) => x+" "+y //僅含有兩個元素的數組
| case Array(0,_*) => "Strat from 0" //0開始的數組
| case _=> "Something else"
| }
// matchArr: (x: Array[Int])String

scala> matchArr(Array(0))
// res21: String = Only 0
scala> matchArr(Array(0 to 20).flatten)
// res23: String = Strat from 0
5.匹配Option
opt match{
case Some(info) => info....
case None => ....
}
6.匹配case class 樣例類
apply
unapply
1.5 匹配中加if守衛
express:Any match {
case x:Int if x%2==0 => x...
}
1.6 使用模式匹配類進行類型轉換
在scala,咱們傾向使用這樣的模式匹配,而不是isInstanceOf()操做符。
eg:
Animal a=new Dog();
if(a.isInstanceOf[Cat]){
val c:Cat=a.asInstanceOf[Cat];
c.eat();
}
被模式匹配取代
a match{
case a:Cat => c.eat();
}

 

3.封閉類sealed class
樣本類的超類被封閉(sealed),封閉類除類定義文件外不能添加子類.

模式匹配完成後須要確保全部狀況皆被考慮,所以Scala編譯器會檢測match表達式所遺漏的模式組合

sealed abstract class Expr
case class Number( n :Int) extends Expr
case class Sum(e1 : Expr , e2 : Expr) extends Expr
case class Mul(e1 : Expr , e2 : Expr) extends Expr

如何定義存在可能樣本遺漏的模式匹配
def getType(a:Expr):String =
a match{
case Number(n) => 「Number「
case Sum(m,n) => 「Sum「
}

warning : match is not exhaustive
case _ =>
添加註解
def getType(a:Expr):String = (a: @unchecked) match {...}

 


4.偏函數
1.定義
被包在花括號內的一組case語句是一個偏函數--一個並不是對全部輸入值都有定義的函數。它是PartialFuncation[A,B]類的一個實例。(A是參數類型,B是返回類型)
Scala中的PartialFunction是一個Trait,其的類型爲PartialFunction[A,B],其中接收一個類型爲A的參數,返回一個類型爲B的結果。
偏函數和其它函數同樣,也定義了apply方法,apply方法會從匹配到的模式計算函數值。該特質有1個方法抽象方法:def isDefinedAt(a: A):Boolean,isDefinedAt方法決定了該方法的參數是否在給定的偏函數的定義域內,若是返回結果爲true,表示在,不然不在。
例如:
scala> val pf:PartialFunction[Int,String] = {
| case 1=>"One"
| case 2=>"Two"
| case 3=>"Three"
| case _=>"Other"
| }
pf: PartialFunction[Int,String] = <function1>

scala> pf(1)
res0: String = One

scala> pf(2)
res1: String = Two

scala> pf(3)
res2: String = Three

scala> pf(4)
res3: String = Other

偏函數內部有一些方法,好比isDefinedAt、OrElse、 andThen、applyOrElse等等。

1.isDefinedAt : 這個函數的做用是判斷傳入來的參數是否在這個偏函數所處理的範圍內。
剛纔定義的pf來嘗試使用isDefinedAt(),只要是Int類型都是正確的,由於有case _=> "Other"這一句。若是換成其餘類型就會報錯。
若是將case _=> "Other"這一行去掉,執行pf(4)則會拋出MatchError異常

2.orElse : 將多個偏函數組合起來使用,效果相似case語句。
scala> val onePF:PartialFunction[Int,String] = {
| case 1=>"One"
| }
onePF: PartialFunction[Int,String] = <function1>

scala> val twoPF:PartialFunction[Int,String] = {
| case 2=>"Two"
| }
twoPF: PartialFunction[Int,String] = <function1>

scala> val threePF:PartialFunction[Int,String] = {
| case 3=>"Three"
| }
threePF: PartialFunction[Int,String] = <function1>

scala> val otherPF:PartialFunction[Int,String] = {
| case _=>"Other"
| }
otherPF: PartialFunction[Int,String] = <function1>

scala> val newPF = onePF orElse twoPF orElse threePF orElse otherPF
newPF: PartialFunction[Int,String] = <function1>

scala> newPF(1)
res0: String = One

scala> newPF(2)
res1: String = Two

scala> newPF(3)
res2: String = Three

scala> newPF(4)
res3: String = Other

這樣,newPF跟原先的pf效果是同樣的。
3.andThen: 至關於方法的連續調用,好比g(f(x))。
scala> val pf1:PartialFunction[Int,String] = {
| case i if i == 1 => "One"
| }
pf1: PartialFunction[Int,String] = <function1>

scala> val pf2:PartialFunction[String,String] = {
| case str if str eq "One" => "The num is 1"
| }
pf2: PartialFunction[String,String] = <function1>

scala> val num = pf1 andThen pf2
num: PartialFunction[Int,String] = <function1>

scala> num(1)
res4: String = The num is 1

pf1的結果返回類型必須和pf2的參數傳入類型必須一致,不然會報錯。

4.applyOrElse:它接收2個參數,第一個是調用的參數,第二個是個回調函數。若是第一個調用的參數匹配,返回匹配的值,不然調用回調函數。
scala> onePF.applyOrElse(1,{num:Int=>"two"})
res5: String = One

scala> onePF.applyOrElse(2,{num:Int=>"two"})
res6: String = two

在這個例子中,第一次onePF匹配了1成功則返回的是"One"字符串。第二次onePF匹配2失敗則觸發回調函數,返回的是"Two"字符串。

===============================插值器=============================

2.10後推出 有 s f raw


s 字符串插值器
在任何字符串前加上s,就能夠直接在串中使用變量了
val name="James"
println(s"Hello,$name")

f 插值器
在任何字符串字面前加上 f,就能夠生成簡單的格式化串,功能類似於其餘語言中的 printf 函數。
val height=1.9d
val name="James"
println(f"$name%s is $height%2.2f meters tall")

raw 插值器
除了對字面值中的字符不作編碼外,raw 插值器與 s 插值器在功能上是相同的。
scala>s"a\nb"
res0:String=
a
b 這裏,s 插值器用回車代替了\n。而raw插值器卻不會如此處理。

scala>raw"a\nb"
res1:String=a\nb 當不想輸入\n被轉換爲回車的時候,raw 插值器是很是實用的


===============================命名參數和可變參數=============================
14,函數的命名參數和可變參數
def number(hundreds: Int, tens: Int, ones: Int) = 100 * hundreds + 10 * tens + ones

i,正常調用number函數
number(2, 3, 5)

ii,帶有命名參數的調用,參數順序能夠變化
number(tens = 3, hundreds = 2, ones = 5)

iii,部分帶有命名參數的調用,要求沒有使用命名參數的位置類型必須對應,使用
命名參數的能夠變換順序number
number(2, ones = 5, tens = 3)

iv,scala可使用可變參數,同java同樣可變參數放在參數列表最後一位且只能有一個
def show(str:String,strs:String*)={
println("first word:"+str)
strs.foreach(println _) //使用可變參數當作數組來使用
}

v,調用可變參數方法時 枚舉傳參 或者 集合:_* 傳參
show("hello","world","briup")
var arr = Array("world","briup")
show("hello",arr:_*)

 


===============================異常處理=====================================


15,異常處理
i,scala裏面沒有檢查型異常,即必需要處理的異常

ii,scala函數 可使用throw 拋出異常
def show(msg:String)={
if(msg == ""){
throw new Exception("msg is empty")
}
println(msg)
}

iii,scala 能夠用try catch finaly捕獲異常,catch對於異常的
捕獲使用的是模式匹配
try {
show("")
}catch {
case e1:NullPointerException => e1.printStackTrace()
case e2:Exception => e2.printStackTrace()
case _ => println("特殊異常") //利用_匹配不是e1 e2類型的異常
}finally {
println("默認執行")
}

iv,若是方法有返回值,按照處理異常的含義,即便發生異常,也要把值進行返回
def readFromFile(file:String):List[String]={
try{
Source.fromFile(file).getLines().toList
}catch {
case e:Exception => List()
}
}

iv,利用Option None Some 處理異常
Option[A] 是一個可能有值也可能沒值的容器
def readFromFileOption(file:String):Option[List[String]]={
try{
Some(Source.fromFile(file).getLines().toList)
}catch {
case e:Exception => None
}
}

Option有兩個子類別,Some和None。當程序回傳Some的時候,表明這個函式成功地給了你一個List,而你能夠透過get()函數拿到那個List,若是程序返回的是None,則表明沒有List能夠給你。

因此Option存在的意義, 就是爲了在代碼中註明, 讓你們一看就知道: "這個東西多是空的! 大家用的時候給我當心點" 這樣的暗示.
有了這個暗示, 你可就不能隨意取出option裏面的東西了, 警醒你每次使用, 都要先判斷. isEmpty 或是 nonEmpty


v,利用Try Success Failure處理異常
Try[A] 則表示一種計算: 這種計算在成功的狀況下,返回類型爲 A 的值,在出錯的狀況下,返回 Throwable

def readFromFileTry(file:String):Try[List[String]]={
Try(Source.fromFile(file).getLines().toList)
}

var result = readFromFileTry("src/test.txt")
result match {
case n:Success[List[_]] => n.get.foreach(println(_));
case m:Failure[List[_]] => println("error");
}

vi,爲了保證和java相互操做 建議在會throw 異常的scala函數上用註解標識,
那麼java代碼在調用此函數時,會提示要處理異常
@throws(classOf[Exception])

 

 

============集合/數組/元組(集合/數組會使用便可)=====================

數組

1.數組:存放一系列元素的容器
1.分類:
不可變數組 定長數組 Array
可變數組 緩衝數組 數組緩存 ArrayBuffer (集合,Seq)
ArrayBuffer位於scala.collection.mutable包下。
2.Array數組
2.1定義方式
1.經過類構建
eg:
val arr=new Array[T](size);
2.經過對象構建(統一對象構建原則)
eg:
val arr2=Array("hello","scala","java");
val arr3=Array.apply(1,2,3,4);
val set=Set(1,2,34,5)
2.2 取值
arr(index)
本質上調用的arr.apply(index)這個方法
arr.take(num)
arr.takeRight(num)
arr.takeWhile(pf:T=>Boolean)
2.3 賦值
arr(index)=值
arr.update(index,值)
2.4 遍歷數組
for(elem <- arr){...}
for(index <- 0 until arr.length){...}
arr.foreach(println)
2.5 獲取數組的長度
arr.length
arr.size
3.ArrayBuffer數組緩衝
2.1定義方式
1.經過類構建
eg:
import scala.collection.mutable.ArrayBuffer
val arrBuffer=new ArrayBuffer[T]();
2.經過對象構建(統一對象構建原則)
eg:
val aeeBuffer=AeeayBuffer(1,2,3)
2.2添加元素
+: ++ ++: +=: ++=: append appendAll insert insertAll
須要注意的是:
1. 當方法名中有一個+號時,指的是添加 一個元素,返回一個新的集合/數組
2. 當方法名中有兩個+號時,指的是添加 一個集合/數組容器,返回一個新的集合/數組
3. 當方法名中出現=號時,指的是會修改原集合。(只有可變集合纔有包含=的方法)
4. 當方法名中沒有=號時,不會修改原集合/數組,通常只會返回一個新的集合/數組
2.3移除元素
- -- -= --= remove(index) remove(index,count) drop(count) dropRight(count) dropWhile(pf:T=>Boolean)
2.4常見方法
take takeRight takeWhile count
算數集合:sum product max min
排序:
sorted 按照集合類型默認排序規則進行排序(默認升序)
sortBy 按照自定義指定規則進行排序
sortWith自定義升序仍是降序排列
遍歷輸出:foreach
轉換:map filter
val result=for(elem <- arr if elem %2==0)yield elem*2
val newArr=arr.filter(_%2==0).map(_*2)
val newArr=
arr.filter(
(x:Int) => {x%2==0}
).map(
(x:Int) => { x*2 }
)

元組: Tuple1 - Tuple22
與數組同樣,元組也是不可變的,但與數組不一樣的是元組能夠包含不一樣類型的元素。
元組的實際類型取決於它的元素的類型,好比 (99, "runoob") 是 Tuple2[Int, String]。 ('u', 'r', "the", 1, 4, "me") 爲 Tuple6[Char, Char, String, Int, Int, String]。
目前 Scala 支持的元組最大長度爲 22。對於更大長度你可使用集合,或者擴展元組。

1 若干個單個的值包含在圓括號便構成元組:
eg:
val t = new Tuple3(1 , 1.2,'A')
val g=(1 , 1.2,'A') 三元 元組 //(Int,Double,Char)類型的元組

2 利用方法_一、_二、_3訪問元組的組元
val h=g._1 或 val h=g _1
或者利用隱式的模式匹配
val (first,second,three)=(1,3.14,"Free");
val (first,second,_)=(1,3.14,"hhhhhhhhhhhh")
val (name,age,phone,address)=("tom",23,110,"南昌")
3 元組能夠用於函數須要返回不止一個值得狀況。
舉例來講,StringOps的partition方法返回的是一對字符串,分別包含了知足某個條件和不知足條件的字符:"New York".partition(_.isUpper)
5 注意區分下邊兩個的不一樣
val x,y,z=(1,"hello",2)
val (x,y,z)=(1,"hello",2)

 

映射: Map(Map集合中每一個元素是一個二元元組)
Map 也叫哈希表(Hash tables)。
1 二元元組的表示方法:
(key,value) 或 key -> value
2 分爲可變映射和不可變映射
scala的集合系統的區分了可變( mutable )和不可變(immutable )集合。一個mutable 集合可以更新甚至擴展空間,這意味着你能改變,增長,或者刪除一個集合的元素。 一個immutable集合,恰好相反,不能改變。你仍然能夠作一些相似的增長,刪除,或者更新,可是實際上他返回了一個新的對象,這裏面就是指返回了一個新的集合,而老的集合沒有改變。

mutable.Map[K,V]
immutable.Map[K,V]
Map <==> immutable.Map <==> Predef.Map
注意:
scala.collection.Map 是immutable.Map和mutable.Map的超類
Scala優先採用不可變集合, scala.collection 包中的伴生對象產出不可變的集合
3 構建Map映射對象
Map 是一個trait 和 object
所以構建方式只有:統一對象構建原則
Map(elem1,elem2,elem2,...)
<===>
Map.apply(elem1,elem2,elem2,...)
4 構建一個空集合,可使用empty方法
import scala.collection.mutable;
val mutableMap=mutable.Map.empty[K,V]
var A:Map[Char,Int] = Map()

5 經過key獲取value值
三種方式:
map.apply(key)
map.get(key)
map.getOrElse(key,defaultValue)
6 添加元素 + ++ ++: (+= ++=) insert insertAll append appendAll

7 移除元素 - -- (-= --=) remove drop dropRight

8 遍歷集合
eg:
for(elem <- map){
val key=elem._1
val value=elem._2
}
或:
for( (key,value) <- map ){
println(key+":"+value)
}
只遍歷key值
map.keys
map.keySet
map.keysIterator
只遍歷value值
map.values
map.valuesIterator

9 拉鍊操做
zip 將兩個集合進行"等值鏈接"
zipAll 將兩個集合進行"全鏈接",三個參數,第一個參數爲鏈接的集合;第二個參數爲原集合元素不足時的補位元素;第三個參數爲鏈接集合元素不足時的補位元素;
zipWithIndex 將集合中的每一個元素變成一個二元元組,二元元組的_2即位當前元素在集合中的索引。

unzip 將容器中的二元元組拆分,將每一個二元元組中的_1放到一個集合中,_2的放到一個集合中。即拆分紅兩個集合。
unzip3 將容器中的三元元組拆分,將每一個三元元組中的_1放到一個集合中,_2的放到一個集合中,_3的放到一個集合中。即拆分紅了三個集合。

eg:
val price=List(2,10,8)
val num=List(10,10,10)

val collection=list1.zip(list2)
val newColl=for( (price,num) <- collection )yield{
price*num
}.sum

val count=collection.map(x=> x._1*x._2).sum


===================集合 總體類的結構===============
1.集合
1.集合分爲: 序列 集 映射
Traversable(Trait)
|
Iterable(Trait)
———————————————————————————-
| | |
Seq Set Map(Trait/object)

2.Seq 是一個有前後次序的值得序列,容許存放重複元素。
2.1總體上分爲:索引序列IndexedSeq,線性序列(鏈表)LinearSeq.
Seq
———————————————————————————————————————————————-
| | |
IndexedSeq Buffer LinearSeq
| | |
Array Vector Range | List LinkedList
String StringBulid ArrayBuffer Queue Stack Stream View
ListBuffer
IndexSeq索引序列:容許咱們經過整型的下標快速訪問任意元素,如ArrayBuffer是帶下標的。
LinearSeq線性序列:被分爲了頭尾部分,而且用head,tail和isEmpty方法等。

注意:Array其實不是真正的序列,是經過將Array包裝成WrappedArray(mutable),才能夠像集合同樣使用。

arr.
buffer.
3.Set是一組沒有重複元素的集合。
Set
———————————————————————————
| | | |
BitSet HashSet ListSet SortedSet
|
TreeSet
在SortedSet中,元素以某種排過序的順序被訪問。
4.Map是一組(K,V)對偶,其中鍵必須是惟一的。
Map
—————————————————————————————————
| | | |
HashMap LinkedListMap ListMap SortedMap
|
TreeMap
SortedMap按照鍵的排序訪問。
5.每一個Scala集合特質或類,都有一個帶有apply方法的伴生對象,這個apply方法能夠用來構建該集合中的實例。
eg:
Iterable(0xFF, 0xFF00, 0xFF0000)
Seq(color.RED, color.GREEN, Color.BLUE)
Map(color.RED -> -0xFF0000, Color.GREEN -> 0xFF00, Color.BLUE -> 0xFF)
SortedSet("Hello" , "World")
2.Seq的一些具體實現類
2.1序列
Vector是ArrayBuffer的不可變版本,一個帶下標的序列,支持快捷的隨機訪問,以樹形結構的形式實現。
Range表示一個整數序列,只存儲 起始值,結束值和增值, 用 to 和 until 方法來構造Range對象。

2.2列表
列表要麼是Nil(空表),要麼是一個head元素和一個tail,tail又是一個列表。
val digits = List(4,2)
digits.head //4
digits.tail //List(2)
digits.tail.head // 2
digits.tail.tail //Nil

:: 操做符從給定的頭和尾建立一個新的列表。
9 :: List(4,2) // List(9,4,2)
9 :: 4 :: 2 :: Nil // :: 是右結合,列表從末端開始構建
9 :: ( 4 :: (2 :: Nil ) )

求和,除了遍歷外,能夠用 遞歸 模式匹配

def sum(lst : List[Int]): Int =
if( lst == Nil) 0 else lst.head + sum(lst.tail)

def sum(lst:List[Int]): Int = lst match{
case Nil => 0
case h :: t => h+sum(t) // h 是 lst.head, 而t是lst.tail, ::將列表"析構"成頭部和尾部
}
直接使用List的方法
List(9,4,2).sum
2.3可變列表ListBuffer
LinkedList, elem指向當前值,next指向下一個元素
DoubleLinkedList多帶一個prev
例1:將全部負值改成0
val lst = scala.collection.mutable.LinkedList(1,-2,7,-9)
var cur = lst
while(cur != Nil){
if(cur.elem<0) cur.elem = 0
cur = cur.next
} // (1,0,7,0)
例2: 去除每兩個元素中的一個
var cur = lst
while(cur != Nil && cur.next != Nil){
cur.next = cur.next.next
cur = cur.next
}
注:當要把某個節點變爲列表中的最後一個節點,不能講next 設爲Nil 或 null, 而將它設爲LinkedList.empty。
3.Set的一些具體實現類
3.1 HashSet 不重複元素的集合,以哈希集實現,元素根據hashCode方法的值進行組織
Set(2,0,1) + 1 // (2,0,1)
HashSet(2,3,0)
3.2 LinkedHashSet,鏈式哈希集 記住元素被插入的順序
val weekdays = scala.collection.mutable.LinkedHashSet(1,2,3,4)
3.3 排序的集
scala.collection.immutable.SortedSet(1,2,3,4) // 用紅黑樹實現的
3.4 位集(bit set), 以一個字位序列的方式存放非負整數,若是集中有i,則第i個字位是1
高效的實現,只要最大元素不是特別大。

位集合是由單字或多字的緊湊位實現的非負整數的集合。其內部使用Long型數組來表示。第一個Long元素表示的範圍爲0到63,第二個範圍爲64到127,以此類推(值爲0到127的非可變位集合經過直接將值存儲到第一個或第兩個Long字段的方式,優化掉了數組處理的消耗)。對於每一個Long,若是有相應的值包含於集合中則它對應的位設置爲1,不然該位爲0。這裏遵循的規律是,位集合的大小取決於存儲在該集合的最大整數的值的大小。假如N是爲集合所要表示的最大整數,則集合的大小就是N/64個長整形字,或者N/8個字節,再加上少許額外的狀態信息字節。
所以當位集合包含的元素值都比較小時,它比其餘的集合類型更緊湊。位集合的另外一個優勢是它的contains方法(成員測試)、+=運算(添加元素)、-=運算(刪除元素)都很是的高效。

BitSet表明一個由小整數構成的容器,這些小整數的值表示了一個大整數被置1的各個位。好比說,一個包含三、2和0的bit集合能夠用來表示二進制數1101和十進制數13. (能夠經過bit.toBitMask來測試) 1110


BitSet內部的使用了一個64位long型的數組。數組中的第一個long表示整數0到63,第二個表示64到27,以此類推。因此只要集合中最大的整數在千之內BitSet的壓縮率都是至關高的。

BitSet操做的運行時間是很是快的。查找測試僅僅須要固定時間。向集合內增長一個項所需時間同BitSet數組中long型的個數成正比,但這也一般是個很是小的值。這裏有幾個關於BitSet用法的例子:

scala> val bits = scala.collection.immutable.BitSet.empty
bits: scala.collection.immutable.BitSet = BitSet()
scala> val moreBits = bits + 3 + 4 + 4
moreBits: scala.collection.immutable.BitSet = BitSet(3, 4)
scala> moreBits(3)
res26: Boolean = true
scala> moreBits(0)
res27: Boolean = false
Scala提供 可變和不可變的兩個 BitSet類

contains 檢查是否包含, subsetOf 檢查集的全部元素是否被另外一個集包含
val digits = Set(1,7,2,9)
digits contains 0 // false
Set(1,2) subsetOf digits // true
3.5 集的操做
合集 union | ++
交集 intersect &
差集 diff &~ --

推薦使用: ++ & --
4.往集合中添加移除元素推薦操做:
4.1 通常而言,+用於將元素添加到無前後次序的集合,而+:和:+則是將元素添加到有前後次序的集合的開頭或末尾。
Vector(1,2,3) :+ 5 //Vector(1,2,3,5)
1 +: Vector(1,2,3) //Vector(1,1,2,3)
4.2 以冒號結尾的操做符,+:是右結合的,這些操做符都返回新的集合

4.3 可變集合有 +=操做符 用於修改左側操做元
val numbers = ArrayBuffer(1,2,3)
numbers += 5 // 將 5 添加到 numbers

4.4 不可變集合,能夠在var上使用+=或:+=
var numbers = Set(1,2,3)
numbers += 5 // numbers 設爲不可變的集numbers + 5
var numberVector = Vector(1,2,3)
numbersVector :+= 5 // 向量沒有+操做符,只有:+
思考: mutable.LinkedList中爲何沒有帶=號的方法????
5.如何選擇一個集合
1.根據集合的特色選擇其中一種集合。
2.想要可變的仍是不可變的集合。

如何選擇Seq集合中的具體類型:
推薦能夠優先採用下邊的集合。
通用的序列集合:
不可變 可變
索引: Vector ArrayBuffer
線性鏈表: List ListBuffer

不可變序列集合:
索引 線性 描述
List 對 單鏈表
Queue 對 先進先出的數據結構
Range 對 整數值範圍
Stack 對 後進先出
Stream 對 與鏈表類似,可是延遲而且持久。適用於大型或無限序列
String 對 不可變的,索引字符序列
Vector 對 split和join很是有效率的實現

可變序列集合:
索引 線性 描述
Array 對 元素是可變的,但集合長度不可變
ArrayBuffer 對 元素可變,集合長度可變
ArrayStack 對 後進先出數據結構。
DoubleLinkedList 對 單鏈表,可是有一個prev前置指向
LinkedList 對 可變的單鏈表
ListBuffer 對 像ArrayBuffer,但依靠鏈表
Queue 對 先進先出
Stack 對 後進先出
StringBuilder 對

如何選擇Map集合中的具體類型:
HashMap LinkedHashMap ListMap Map SortedMap TreeMap

如何選擇Set集合中的具體類型:
HashSet LinkedHashSet ListSet TreeSet Set SortedSet BitSet
6.別的集合類(表現像集合同樣的類型)
Enumeration
Iterator
Option 包含一個或零個元素的集合。
Tuple 元組類 Tuple1 到 Tuple22
7.集合類中的通用方法:
1.過濾方法
collect drop dropWhile filter filterNot find foldLeft foldRight head headOption init last lastOption reduceLeft reduceRight remove slice tail take takeWhile union diff intersect distinct等
2.轉化方法
+ ++ - — diff distinct collect flatMap map reverse sortWith takeWhile zip zipWithIndex zipAll等
以及一系列的to****方法,將當前集合轉化成其餘集合類型(Array,Buffer,Vector等)
3.分組方法
groupBy partition sliding span splitAt unzip unzip3 等
4.信息和數學方法
canEqual contains containsSlice count endsWith exists find forAll hasDefiniteSize indexOf indexOfSlice indexWhere max min nonEmpty product segmentLength size startsWith sum 等
5.其餘
par view flatten foreach mkstring
6.化簡 摺疊 掃描
6.1
reduce
reduceLeft
reduceRight

6.2
fold
foldLeft /:
foldRight :\

6.3 scanLeft,scanRight, 獲得包含全部中間結果的集合
scan
scanLeft
scalRight
做業:獲取一個字符串中每一個字符出現的頻次。
1.for現實
2.摺疊實現
val freq = scala.collection.mutable.Map[Char, Int]() // 可變映射
for( c <- "Mississippi"){
freq(c) =freq.getOrElse(c,0)+1 // Map('i' ->4, 'M' -> 1, 's' -> 4, 'p' ->2)
}

val map=(Map[Char, Int]() /:"Mississippi"){(m,c) => m + (c -> (m.getOrElse(c,0) +1)}
8.Iterator
相對於集合而言是一個"懶"的替代品,只有在須要時纔去取元素,若是不須要更多元素,不會付出計算剩餘元素的代價
對於那些完整構造須要很大開銷的集合,適合用迭代器
如Source.fromFile產出一個迭代器,由於整個文件加載進內存不高效。
迭代器的兩種用法
while(iter.hasNext) iter.next()
for(elem <- iter) 對elem操做
上述兩種循環都會講迭代器移動到集合末端,不能再被使用,
調用 map filter take等轉換方法,返回值爲集合,所以指針不發生變化。
調用 count sum length find方法後,返回值爲單個值 迭代器會位於集合的末端,不能使用
9.Stream
9.1 迭代器每次調用next都會改變指向,若是要緩存以前的值,可使用流
9.2 流是一個尾部被懶計算的不可變列表,也就是說只有須要時才計算
def numsForm(n:BigInt) : Stream[BigInt] = n #:: numsForm(n+1) // #:: 操做符 構建出來的是一個流

var tenOrMore = numsForm(10) // Stream(10,?), 其尾部是未被求值得
tenOrMore.tail.tail.tail // Stream(13,?)
val squares = numsForm(1).map{ x=> x*x) // Stream(1,?)
9.3 使用force去流強制求值
squares.take(5).force // Stream(1,4,9,16,25)
squares.force // 會嘗試對一個無窮流的全部成員求值,最後 OutOfMemoryError
9.4 迭代器能夠用來構造一個流 經過toStream方法
Source.fromFile("").getLines返回一個Iterator[String],用這個迭代器,對於每一行只能訪問一次,而流將緩存訪問過的行,容許從新訪問
val words = Sourcce.fromFile("/usr/share/dict/words").getLines.toStream
words // Stream(A, ?)
words(5) // Aachen
words // Stream(A, A'o, AOL, AOL's, Aachen, ?)
10.View
10.1 相似流的懶理念
10.2 與流的不一樣
一、連第一個元素都不會求值
二、不會緩存求過的值
10.3 懶試圖的好處:能夠避免在多種變換下產生的中間集合
(0 to 1000).map(pow(10,_)).map(1/_) //先第一個map,再第二個map, 構 建了一箇中間集合
(0 to 1000).view.map(pow(10,_)).map(1/_).force // 記住兩個map操做 每一個元素被兩個操做同時執行,不須要額外構中間集合
11.並行集合 par
11.1 爲了更好利用計算機的多個處理器,支持併發一般是必需的若是coll是個大型集合,那麼
coll.par.sum //併發求和,par方法產出當前集合的一個並行實現,該實 現會盡量地並行執行集合方法
coll.par.count(_ % 2 ==0) //計算偶數的數量
11.2 對數組、緩衝、哈希表、平衡樹而言,並行實現會直接重用底層實際集合的實現,因此很高效
11.3 能夠經過對要遍歷的集合應用.par並行化for循環
for( i <- (0 until 100).par) print( i + " " ) //數字是按照做用於 該任務的線程產出的順序輸出
在for/yield循環中,結果是依次組裝的
for( i <- (0 until 100).par) yield i +" "
11.4 par返回的並行集合擴展自ParSeq ParSet Parmap,都是ParIterable的子類 型,不是Iterable的子類型,因此不能將並行集合傳遞給預期Iterable Seq Set Map的方法。
11.5 能夠用to方法將並行集合轉換回串行的版本。
eg:
eg:查看打印的數字順序
(0 until 10).par.foreach(println)
(0 until 10).foreach(println)
如下代碼獲取到參與並行計算的線程:
(0 to 10000).par.collect{case _ => Thread.currentThread.getName}.distinct
(0 to 10000).collect{case _ => Thread.currentThread.getName}.distinct
12.與Java集合互調用
12.1 藉助於scala.collection.JavaConverters對象中的靜態方法。
asScala
asJava
12.2 Java2Scala集合舉例:Java中的集合只能轉化成Scala中可變集合
import scala.collection.JavaConverters._;
//1.定義一個java的集合對象
val list=new util.ArrayList[String]();
list.add("java");
list.add("scala");
println(list);
//2.遍歷集合對象
list.forEach(new Consumer[String] {
override def accept(t: String): Unit = {
println(t);
}
})
//3.轉化成Scala集合
val list_s:mutable.Buffer[String]=list.asScala;
//4.遍歷Scala集合
list_s.foreach(println _)
val list_s2:mutable.Iterable[String]=list.asScala;
val list_s3:Seq[String]=list.asScala;
list_s2.foreach(println _)
list_s3.foreach(println _)
//5.其餘方法
val a1=asScalaBuffer(list);
val a2=asScalaIterator(list.iterator());
12.3 Scala2Java集合舉例:
import scala.collection.JavaConverters._
//1.定義一個Scala數組
val a1=new Array[Int](3);
val a2=(1 to 10 ).toArray;
//a2.asJava;
//2.定義一個Scala緩衝
val buffer=a2.toBuffer;ArrayBuffer
val buffer_j=buffer.asJava;
buffer_j.forEach(new Consumer[Int] {
override def accept(t: Int): Unit = {
println("java:"+t)
}
})
val source = new scala.collection.mutable.ListBuffer[Int]
val target: java.util.List[Int] = source.asJava
val other: scala.collection.mutable.Buffer[Int] = target.asScala
12.3 Java調用Scala的方法時,若是參數爲可變參時,不能直接調用,須要咱們在scala中定義方法時,添加註解@varargs
@varargs
def varargs( name:String*)={
name.foreach(println)
}


====================函數==============================
Scala 有方法與函數,兩者在語義上的區別很小。Scala 方法是類的一部分,而函數是一個對象能夠賦值給一個變量。換句話來講在類中定義的函數便是方法。

Scala 中的方法跟 Java 的相似,方法是組成類的一部分。

Scala 中的函數則是一個完整的對象,Scala 中的函數其實就是繼承了 Trait 的類的對象。

Scala 中使用 val var 語句能夠定義函數,def 語句定義方法。

函數和方法的區別
一、函數可做爲一個參數傳入到方法中,而方法不行。

二、在Scala中沒法直接操做方法,若是要操做方法,必須先將其轉換成函數。有兩種方法能夠將方法轉換成函數:
val f1 = m _
在方法名稱m後面緊跟一個空格和下劃線告訴編譯器將方法m轉換成函數,而不是要調用這個方法。 也能夠顯示地告訴編譯器須要將方法轉換成函數:
val f1: (Int) => Int = m
一般狀況下編譯器會自動將方法轉換成函數,例如在一個應該傳入函數參數的地方傳入了一個方法,編譯器會自動將傳入的方法轉換成函數。

三、函數必需要有參數列表,而方法能夠沒有參數列表
匿名函數
scala> val sayHello = (name: String) => println("my name is:" + name)
sayHello: String => Unit = <function1>

scala> sayHello("cyony")
my name is:cyony
sayHello變量就是一個函數,它沒有本身的函數名,只定義了函數簽名,以及函數體,返回類型爲Unit,能夠看到編譯器自動爲這個匿名函數取名爲function1。在實際調用時,直接調用這個函數變量,傳入一個String類型的值,便可。

函數傳參
1.Scala的解釋器在解析函數參數(function arguments)時有兩種方式:

傳值調用(call-by-value):先計算參數表達式的值,再應用到函數內部;
傳名調用(call-by-name):將未計算的參數表達式直接應用到函數內部

object Test {
def main(args: Array[String]) {
delayed(time());
}

def time() = {
println("獲取時間,單位爲納秒")
System.nanoTime
}
def delayed( t: => Long ) = {
println("在 delayed 方法內")
println("參數: " + t)
t
}
}

以上實例中咱們聲明瞭 delayed 方法, 該方法在變量名和變量類型使用 => 符號來設置傳名調用


高階函數
高階函數(Higher-Order Function)就是操做其餘函數的函數。

Scala 中容許使用高階函數, 高階函數可使用其餘函數做爲參數,或者使用函數做爲輸出結果。

如下實例中,apply() 函數使用了另一個函數 f 和 值 v 做爲參數,而函數 f 又調用了參數 v:

object Test {
def main(args: Array[String]) {

println( apply( layout, 10) )

}
// 函數 f 和 值 v 做爲參數,而函數 f 又調用了參數 v
def apply(f: Int => String, v: Int) = f(v)

def layout[A](x: A) = "[" + x.toString() + "]" }

相關文章
相關標籤/搜索