scala學(xué)習(xí)筆記
第2章 變量和數(shù)據(jù)類型
基本數(shù)據(jù)
- scala的核心數(shù)據(jù)為四種 :字面量、值、變量、類型
- 值使用val來(lái)定義、變量使用var來(lái)定義
val x: Int =20var x: Int =30,定義值和變量 - 在scala中,值優(yōu)先于變量,這是因?yàn)榭梢詾樵创a帶來(lái)穩(wěn)定性和可預(yù)測(cè)性。
數(shù)值型類型
- Byte
- Short
- Int
- Long
- Float
- Double
scala不允許從較高等級(jí)類型自動(dòng)轉(zhuǎn)換到較低等級(jí)類型,但是可以使用toType方法手動(dòng)完成類型間的轉(zhuǎn)換,所有數(shù)值型都有這樣一個(gè)方法。例如:toInt\toString\toDouble、、
字符串
注:雙引號(hào)為字符串String,單引號(hào)為字符Char
與數(shù)值型類似,String類型也支持使用數(shù)學(xué)運(yùn)算符。
"string"+"abc"、"string2"*2等等可以使用三重引號(hào)創(chuàng)建多行String。多行字符串是字面量,所以如果其中使用了反斜杠,不要認(rèn)為是一個(gè)特殊的轉(zhuǎn)義字符。
字符串內(nèi)插
- 要在一個(gè)String中加入值或變量,更直接的一種方法是利用字符串內(nèi)插。
- println(s"Pi,using 355/113,is about $approx");
- 如果引用中有非字字符,或者如果引用與周圍文本無(wú)法區(qū)分,就要使用大括號(hào):
s"How do you like them ${item}s?"
正則表達(dá)式
- 使用.r函數(shù)將普通的字符串轉(zhuǎn)換為正則表達(dá)式,
val pattern = "scala".r,和java類似。 - 使用findFirstIn 函數(shù)來(lái)查找第一個(gè)匹配的表達(dá)式,pattern findFirstIn input
- 使用findAllIn函數(shù)來(lái)查找所有匹配上的表達(dá)式,但是好像并不會(huì)打印出來(lái),此時(shí)使用mkString(",")函數(shù)來(lái)鏈接兩個(gè)字符串
println((pattern findAllIn input).mkString(",")) - 類似的,使用replaceFirst 和replaceAll ,
input replaceAll ("a.*","a")
等掌握熟練后回過(guò)頭來(lái)繼續(xù)研究。
核心非數(shù)值類型
| 類型名 | 描述 | 可否實(shí)例化 |
|---|---|---|
| Any | Scala中所有類型的根 | 否 |
| AnyVal | 所有值類型的根 | 否 |
| AnyRef | 所有引用(非值)類型的根 | 否 |
| Nothing | 所有類型的子類 | 否 |
| Null | 所有指示null值的AnyRef類型的子類 | 否 |
| Char | Unicode字符 | 是 |
| Boolean | true 或 false | 是 |
| String | 字符串 | 是 |
| Unit(void) | 指示沒(méi)有值 | 否 |
- 注意&&和& 的使用的區(qū)別,一個(gè)是在if判斷條件等中使用,另外一個(gè)是邏輯運(yùn)算。
- -Unit類型相當(dāng)于java、C中的void返回類型,即為空類型。一般用來(lái)定義函數(shù)和表達(dá)式。
類型操作
| 操作名 | 示例 | 描述 |
|---|---|---|
| asInstanceOf | 5.asInstanceOf[Long] | 將一個(gè)值轉(zhuǎn)換為指定類型的值。如果這個(gè)值與新類型不兼容,會(huì)導(dǎo)致一個(gè)錯(cuò)誤 |
| getClass | (7.0/5).getClass | 返回一個(gè)值的類型 |
| isInstanceOf | (5.0).isInstanceOf[Float] | 判斷一個(gè)值的類型是否為指定的類型,如果是則返回true |
| hashCode | "A".hashCode | 返回這個(gè)值的散列碼 |
| to<type> | 20.toByte ,47.toFloat | 轉(zhuǎn)換函數(shù),可以將一個(gè)值轉(zhuǎn)換為一個(gè)兼容的值 |
| toString | (3.0/4.0).toString | 將值顯示為字符串類型 |
- 注意:避免使用asInstanceOf,如果值無(wú)法轉(zhuǎn)換為所請(qǐng)求的類型,asInstanceOf操作會(huì)導(dǎo)致一個(gè)錯(cuò)誤,為了避免這個(gè)操作帶來(lái)的運(yùn)行的錯(cuò)誤,應(yīng)當(dāng)盡可能使用toType完成類型轉(zhuǎn)換。
元組
- 元組是一個(gè)包含兩個(gè)或多個(gè)值的有序容器,所有的這些值可以有不同的類型。相當(dāng)于關(guān)系表中的一個(gè)樣本,data.frame中的一個(gè)元素。(不同于R語(yǔ)言中的向量和數(shù)組,因?yàn)镽中的向量和數(shù)組必須是全部是相同的類型。)
val info = (5,"Korben",true)
- 可以根據(jù)元素的索引訪問(wèn)元組中的單個(gè)元素,從1開(kāi)始。
info._2 - 要?jiǎng)?chuàng)建一個(gè)大小為2的元組,另一種候選形式是利用關(guān)系操作符 (->) 。這是一種表示元組中鍵和鍵值的流行的快捷方式:
val red = "red" -> 15 ,直接創(chuàng)建一個(gè)鍵和鍵值對(duì),相當(dāng)于二元元組
第3章 表達(dá)式和條件式
表達(dá)式塊
- 可以使用大括號(hào)結(jié)合多個(gè)表達(dá)式創(chuàng)建一個(gè)表達(dá)式塊。表達(dá)式有自己的作用域,可以包含表達(dá)式塊中的局部值和變量。塊中的最后一個(gè)表達(dá)式將作為整個(gè)表達(dá)式塊的返回值。
val x=5*20;val amount=x+10、{val a=1;{val b=a*2;{val c=b+4;c}}}
語(yǔ)句
- 語(yǔ)句就是不返回值的表達(dá)式。語(yǔ)句的返回類型為Unit,這種類型指示沒(méi)有值。scala編程中常用的語(yǔ)句包括println()調(diào)用以及值和變量定義。
if...else表達(dá)式塊
val max = if(x>y) x else y
- 類似于java和C中的if...else表達(dá)式。
匹配表達(dá)式
- 匹配表達(dá)式類似C和java中的switch語(yǔ)句,首先會(huì)計(jì)算一個(gè)輸入項(xiàng),并執(zhí)行第一個(gè)匹配模式,然后返回它的值。只有0個(gè)或1個(gè)模式可以匹配。
- scala的匹配表達(dá)式非常靈活,允許匹配各種各樣的項(xiàng),如類型、正則表達(dá)式、數(shù)值范圍和數(shù)據(jù)結(jié)構(gòu)內(nèi)容
語(yǔ)法:使用匹配表達(dá)式
<expression> match {
case <pattern match> => <expression>
[case ...]
}
val x=10;val y=20;
val max = x>y match {
case true => x
case true => y
}
val status=500 ;
val message = status match {
case 200 => "ok"
case 400 => {println("ERROR - we called the service incorrectly")
println("error")
}
case 500 => {println("ERROR - the service encountered an error")
println("error")}
}
語(yǔ)法:模式替換式
值綁定 case <pattern 1>|<pattern 2>.. => <one or more expression>
val day ="mon"
val kind =day match {
case "mon"|"tue"|"wed" |"thu" |"fri" => "weekday"
case "sat"|"sun" => "weekday"
}
- 如果匹配的表達(dá)式?jīng)]有為輸入表達(dá)式提供一個(gè)模式的匹配,則scala會(huì)報(bào)錯(cuò)。
用通用模式匹配
語(yǔ)法:值綁定模式 case <identifier> => <one or more expression>
val message ="Ok"
val status =message match {
case "Ok" => 200
case other => {println(s"Couldn't parse $other")
-1}
}
通配符綁定
通配符是一個(gè)下劃線字符,相當(dāng)于一個(gè)匿名占位符,最后將在運(yùn)行時(shí)替換為一個(gè)表達(dá)式的值。
語(yǔ)法: 通配符模式 case _ => <one or more expression>
- 不能在箭頭右側(cè)訪問(wèn)通配符。
val message ="abc"
val status =message match {
case "Ok" => 200
case _ => {println(s"Couldn't parse $message")
-1
}
}
用模式哨衛(wèi)匹配
- 模式哨兵向值綁定模式增加一個(gè)if表達(dá)式,從而可以為匹配表達(dá)式增加條件邏輯。使用哨兵模式時(shí),只有當(dāng)表達(dá)式返回true時(shí)模式才匹配。
語(yǔ)法:模式哨兵 case <pattern> if <Boolean expression> => <one or more expression> - 與常規(guī)的if表達(dá)式不同,這里的if 表達(dá)式不需要在其分布表達(dá)式的兩邊加小括號(hào)。常規(guī)的if表達(dá)式需要小括號(hào)來(lái)簡(jiǎn)化整個(gè)命令的解析,并從條件表達(dá)式中區(qū)分出布爾表達(dá)式。不過(guò)如果愿意,也可以 添加小括號(hào)。
val res : String =null
res match {
case s if s!=null => println(s"Received '$s'")
case s => println("Error! Received a null res")
}
用模式變量匹配類型
- 利用匹配表達(dá)式完成模式匹配還有一種方法,即匹配輸入表達(dá)式的類型。如果匹配,模式變量可以把輸入值轉(zhuǎn)換為一個(gè)不同的值,然后可以在case塊中使用這個(gè)新值和類型。
語(yǔ)法 : 指定模式變量 case <identifier>:<type> => <one or more expression>
val x: Int =12180;
val y: Any =x ;
y match {
case x:String => s"'x'"
case x:Double => f"$x%.2f"
case x:Float => f"$x%.2f"
case x:Long => s"${x}l"
case x:Int => s"${x}i"}
循環(huán)
- for循環(huán)
語(yǔ)法:用基本for循環(huán)迭代處理 for(<identifier> <- <iterator>)[yield][<expression>]
注意: <-符號(hào)之間必須沒(méi)有空格,否則會(huì)報(bào)錯(cuò)
yield 關(guān)鍵字是可選的。如果表達(dá)式中指定了這個(gè)關(guān)鍵字,調(diào)用的所有表達(dá)式的返回值將作為一個(gè)集合返回。如果沒(méi)有指定這個(gè)關(guān)鍵字,但是制定了表達(dá)式,將會(huì)調(diào)用這個(gè)表達(dá)式,但是不能訪問(wèn)它的返回值。
for(x <- 1 to 7) {println(s"Day $x:")}
val xxx=for(x <- 1 to 7)yield {s"Day $x:"}
for(day <- xxx) println(day)//此時(shí)不需要初始化值day,直接使用for循環(huán)
- 加上yield關(guān)鍵字后,循環(huán)中的數(shù)據(jù)被存到了一個(gè)集合中。
2.迭代器哨兵
- 類似匹配表達(dá)式中的模式哨兵,迭代器哨兵也稱為過(guò)濾器,可以為迭代器增加一個(gè)if表達(dá)式。
語(yǔ)法: 迭代器哨兵 for(<identifier> <- <iterator> if <Boolean expression>)
val threes =for (i <- 1 to 20 if i % 3==0 )yield i
//定義迭代器哨兵
val quote ="a,b,c"
for(t<- quote.split(",");if t!=null ;if t.size>0) println(t)// 和java一樣,集合的大小使用.size,分裂一個(gè)字符串使用.split
- 嵌套迭代器
- 嵌套迭代器是增加到一個(gè)for循環(huán)的額外的迭代器,迭代總數(shù)隨迭代器的個(gè)數(shù)倍增。之所以被稱為嵌套迭代器,是因?yàn)榘阉鼈冊(cè)黾拥酵粋€(gè)循環(huán)中與寫為單獨(dú)的嵌套循環(huán)有相同的效果。
//雙層for循環(huán)
for(x<- 1 to 2 ;y<- 1 to 3){//兩個(gè)條件之間的空格還是必須要的
print(s"$x,$y")}
- while和Do/While循環(huán)
- 除了for循環(huán)外,scala還支持while循環(huán)和do/while循環(huán),不過(guò),在scala中沒(méi)有for循環(huán)常用,因?yàn)樗鼈儾皇潜磉_(dá)式,不能用來(lái)獲取值。
語(yǔ)法: while循環(huán) while(<Boolean expression>)statment
//while循環(huán)
var x=10; while (x>0) x-=1
//do while循環(huán)
val x=0
do println(s"Here I am,x=$x") while (x>0)
//死循環(huán)
var x=0;
do {println(s"here I am ,x=$x");
x+=1;
}while (x>0)
- 具體的差別和java中的定義是一樣的,關(guān)鍵是do while循環(huán)不管條件是否成立,會(huì)先運(yùn)行一次。
第4章 函數(shù)
語(yǔ)法 : 定義無(wú)輸入的函數(shù) def <identifier> = <expression>
def hi ="hi"
語(yǔ)法: 定義函數(shù)時(shí)指定返回類型 def <identifier>: <type>=<expression>定義函數(shù) def <identifier>(<identifier>:<type>[,...]): <type>=<expression>
def multiplier (x:Int,y:Int):Int ={x*y}
multiplier(6,7)
- 這些函數(shù)的函數(shù)體基本上由表達(dá)式或表達(dá)式塊組成,在這里最后一行將成為表達(dá)式的返回值,相應(yīng)的也是函數(shù)的返回值。
- 也可以顯示的使用return來(lái)直接返回一個(gè)函數(shù)的返回值。
過(guò)程
- 過(guò)程是沒(méi)有返回值的函數(shù),以一個(gè)語(yǔ)句結(jié)尾的函數(shù)是一個(gè)過(guò)程。如果有一個(gè)簡(jiǎn)單的函數(shù),沒(méi)有顯示的返回類型,而且最后一個(gè)是一個(gè)語(yǔ)句,scala編輯器就會(huì)推到出這個(gè)函數(shù)的返回類型是Unit,這表示沒(méi)有值。
用空括號(hào)定義函數(shù)
語(yǔ)法: 用空括號(hào)定義函數(shù) def <identifier>()[:<type>]=<expression>
def hi() : String ="hi"
hi()
使用表達(dá)式塊調(diào)用函數(shù)
語(yǔ)法: 用表達(dá)式塊調(diào)用函數(shù) <function identifier><expression block>
遞歸函數(shù)
- 例子
def power(x:Int,n:Int):Long={
if(n>=1) x*power(x,n-1)
else 1
}
嵌套函數(shù)
- 函數(shù)是命令的參數(shù)化表達(dá)式,而表達(dá)式塊是可以嵌套的,所以函數(shù)本身也是可以嵌套的??梢栽诤瘮?shù)中定義另一個(gè)內(nèi)部函數(shù),這個(gè)內(nèi)部函數(shù)只能在該函數(shù)中使用。
def max(a:Int,b:Int,c:Int)={
def max(x:Int,y:Int)=if(x>y) x else y
max(a,max(b,c))
} //這里的嵌套函數(shù)與外部函數(shù)同名,但是由于它們的參數(shù)不同,所有它們之間不會(huì)發(fā)生沖突
方法和操作符
- 方法是類中定義的一個(gè)函數(shù),這個(gè)類的所有實(shí)例都會(huì)有這個(gè)方法。scala 中調(diào)用方法的標(biāo)準(zhǔn)做法是使用中綴點(diǎn)記法,方法名前面有實(shí)例和一個(gè)點(diǎn)分隔作為前綴。
語(yǔ)法 : 用中綴點(diǎn)記法調(diào)用方法 <class instance> <method> [(parameters)]
val s="vacation.jpg"
val isJEPG=s.endWith(".jpg")
// compare、round、floor函數(shù)
val d =65.642
d.round //四舍五入
d.floor //下取整
d.compare(18) //大小比較
- 對(duì)于單個(gè)參數(shù)的方法,直接使用操作符記法來(lái)調(diào)用方法
語(yǔ)法: 用操作符記法調(diào)用方法 <object><method><parameter>
val d=12;
d compare 18;
d + 27;
//string.substring(2,4)
第5章 首類函數(shù)
- 函數(shù)式編程的關(guān)鍵是函數(shù)應(yīng)當(dāng)是首類的?!笆最悺北硎竞瘮?shù)不僅能得到聲明和調(diào)用,還可以作為一個(gè)數(shù)據(jù)類型用在這個(gè)語(yǔ)言的任何地方。
- 如果一個(gè)函數(shù)接受其他函數(shù)作為參數(shù),或者使用函數(shù)作為返回值,這就成為高階函數(shù)。例如:map和reduce
函數(shù)類型和值
- 函數(shù)的類型是其輸入類型和返回值類型的一個(gè)簡(jiǎn)單組合,由一個(gè)箭頭從輸入類型指向輸出類型
- 將函數(shù)賦給一個(gè)值中進(jìn)行存儲(chǔ)
語(yǔ)法:函數(shù)類型 ([<type>,...])=> <type>
def double(x:Int):Int =x*2
double(5)
val myDouble:(Int) => Int =double
myDouble(5)
val myDoubleCopy =myDouble
myDoubleCopy(5)
- myDouble就是一個(gè)值,只不過(guò)與其他值不一樣,它可以調(diào)用double
- 使用通配符為函數(shù)賦值
語(yǔ)法 val <identifier>=<function name> _
def double(x:Int):Int =x*2
val myDouble =double _
val amount=myDouble(20)
- 將函數(shù)賦值,不僅需要將函數(shù)名賦值,而且需要將函數(shù)的參數(shù)類型同時(shí)進(jìn)行賦值
高階函數(shù)
- 高階函數(shù)也是函數(shù),它包含一個(gè)函數(shù)類型的值作為輸入?yún)?shù)或返回值。
//例1
println(apply(layout,10))
def apply(f:Int => String,v:Int) =f(v)
def layout[A](x:A):String ={"["+x.toString+"]"}//泛型函數(shù),輸入值可以為任意的類型,輸出值為String類型
//例2
def safeStringOp(s:String,f:String => String) ={
if(s!=null) f(s) else s
}
def reverser(s:String) = s.reverse
safeStringOp(null,reverser)
safeStringOp("Ready",reverser)
匿名函數(shù)(函數(shù)字面量)
語(yǔ)法:編寫函數(shù)字面量 ([<identifier>:<type>,...]) => <expression>
val doubler =(x:Int) => x*2
val doubled = doubler(22)
- 匿名函數(shù)沒(méi)有固定返回值的類型
//做一個(gè)比較
def max(a:Int,b:Int) ={if(a>b) a else b }//一般函數(shù)定義
val maximize :(Int,Int) => Int =max //將max函數(shù)賦值給maximize值
val maximize =(a:Int,b:Int) => if(a>b) a else b //直接使用匿名函數(shù)來(lái)定義
maximize(48,65)
占位符語(yǔ)法
- 占位符語(yǔ)法是匿名函數(shù)的一種縮寫形式,將命名函數(shù)替換為通配符下劃線。可以在以下情況使用:
- 函數(shù)的顯示類型在字面量之外定義
- 函數(shù)最多只使用一次
def combination(x:Int,y:Int,f:(Int,Int)=>Int)=f(x,y)
combination(23,12,_*_)
- 這里使用了兩個(gè)占位符,這確實(shí)會(huì)使語(yǔ)法更為抽象,它們會(huì)按照位置替換輸入?yún)?shù),如果使用一個(gè)額外的通配符,將會(huì)導(dǎo)致錯(cuò)誤,以為占位符的個(gè)數(shù)必須與輸入?yún)?shù)個(gè)數(shù)一致。
def tripleOp(a:Int ,b:Int,c:Int,f:(Int,Int,Int)=>Int )=f(a,b,c)
tripleOp(23,92,14,_*_+_)
//使用泛型函數(shù)來(lái)定義
def trip[A,B] (a:A,b:A,c:A,f:(A,A,A)=> B)=f(a,b,c)
println(trip[Int,Int](12,22,33,_+_+_))
- 占位符語(yǔ)法在處理數(shù)據(jù)結(jié)構(gòu)和集合時(shí)尤有幫助。
部分應(yīng)用函數(shù)和柯里化
- 柯里化是對(duì)包含多個(gè)參數(shù)的函數(shù)分步計(jì)算,類似于數(shù)學(xué)分析中的分部積分的思想
def factor(x:Int)(y:Int) ==y %x==0
val isEven =factor(2) _
val z =isEven(32)
第6章 常用集合
- 集合框架提供了一些數(shù)據(jù)結(jié)構(gòu)來(lái)收集給定類型的一個(gè)或多個(gè)值,如:數(shù)組、列表、映射、集合樹(shù)
列表、集合映射
- List類型是一個(gè)不可變的單鏈表??勺鳛橐粋€(gè)函數(shù)調(diào)用List來(lái)創(chuàng)建一個(gè)列表,并以逗號(hào)分隔參數(shù)的形式傳入列表的內(nèi)容:
val numbers =List(32,95,24,21,17)
numbers.size //求集合的基數(shù)大小
- 集合中的元素必須是統(tǒng)一類型的,可以初始化集合元素的類型
val x =List[Int] (1,2,3)
println(x.size)
- 集合中的head和tail方法可以查看集合的首部幾個(gè)元素和尾部幾個(gè)元素
- 集合中索引下標(biāo)使用小括號(hào)來(lái)進(jìn)行索引,和matlab中索引的方法是類似的,從0開(kāi)始哦?。?!
x.head
x.tail //注意不能加上小括號(hào)
x(1)
x(3)//此時(shí)會(huì)造成數(shù)組越界
- 使用List.fill來(lái)創(chuàng)建一個(gè)指定重復(fù)數(shù)量的元素列表:
object Test {
def main(args: Array[String]) {
val site = List.fill(3)("Runoob") // 重復(fù) Runoob 3次
println( "site : " + site )
val num = List.fill(10)(2) // 重復(fù)元素 2, 10 次
println( "num : " + num )
}
}
- head函數(shù)為返回一個(gè)列表中的首元素、tail函數(shù)為返回列表中其余的元素
- 集合中的for循環(huán)有兩種,一種是使用for(i <- 1 to x.size) ,另外一種是使用for (i <- x)
- scala中大量使用了高階函數(shù)來(lái)完成迭代、映射、歸約。
val colors=List("red","green","blue")
colors.foreach((c:String)=> println(c))
val sizes =colors.map((c:String)=>c.length)//c.length為字符串的長(zhǎng)度,c.size一樣
val numbers =List(32,95,24,21,17)
val total =numbers.reduce((a:Int,b:Int)=> a+b)
println(sizes)
println(total)
//foreach取一個(gè)函數(shù),對(duì)列表中的每一項(xiàng)分別調(diào)用這個(gè)函數(shù)
//map()取一個(gè)函數(shù),將一個(gè)列表元素轉(zhuǎn)換為另一個(gè)值或類型
//reduce()取一個(gè)函數(shù),將兩個(gè)列表元素結(jié)合為一個(gè)元素
//foreach、map、reduce均為高階函數(shù),輸入的參數(shù)為函數(shù)
- set是一個(gè)不可變的無(wú)序集合,只包含不重復(fù)的唯一元素,不過(guò)其工作與List類似。//類似于java中的HashSet集合
val unique=Set(10,20,30,20,20,10)
val sum =unique.reduce((a:Int,b:Int)=> a+b)
println(sum)
- List和Set的區(qū)別在List中允許出現(xiàn)重復(fù)的元素,而Set中不允許出現(xiàn)重復(fù)的元素。
- Map是一個(gè)不可變的鍵值庫(kù),在Map中,值按照一個(gè)給定的唯一鍵存儲(chǔ),可以使用這個(gè)鍵來(lái)獲取相應(yīng)的值。鍵和鍵值都可以類型參數(shù)化,像創(chuàng)建從整數(shù)到字符串的映射一樣,也可以很容的創(chuàng)建從字符串到整數(shù)的映射。
- 創(chuàng)建Map時(shí),指定鍵-值為元組。可以使用關(guān)系型操作符來(lái)指定鍵和值元組。
val colorMap =Map("red"-> 1, "blue"-> 2, "green" -> 3)
val redRGB =colorMap("red")
val cyanRGB =colorMap("green") | colorMap("blue")
val hasWhite =colorMap.contains("white")//考察鍵值庫(kù)中是否存在鍵為white的鍵
for(i <- colorMap) {println(i)}//使用for循環(huán),和List、Set一樣的操作
- List里面有什么??
- 可以在集合中存儲(chǔ)任何類型的值,而不只是目前為止我們所用的數(shù)字和字符串。
- 可以把一個(gè)列表分解為表頭(head)和表尾(tail),表頭即表的第一項(xiàng),表尾即表中的其余項(xiàng)。
- List是一個(gè)不可變的遞歸數(shù)據(jù)結(jié)構(gòu),所以列表中的每一項(xiàng)都有自己的表頭和越來(lái)越短的表尾。
三種方法來(lái)遍歷List表
- 使用isEmpty方法
val numbers =List(32,95,24,21,17,28,39,40,23,34)
var i=numbers //定義一個(gè)變量來(lái)進(jìn)行遍歷
while(!i.isEmpty){print(i.head+",");i=i.tail}
- 使用遞歸來(lái)進(jìn)行遍歷
val numbers =List(32,95,24,21,17,28,39,40,23,34)
def visit(i:List[Int]):Unit = {if(i.size)>0 {print(i.head+",");visit(i.tail)}}
visit(numbers)
- 調(diào)用Nil實(shí)例作為終結(jié)點(diǎn),所有列表都有一個(gè)Nil實(shí)例作為終結(jié)點(diǎn),所以迭代器可以通過(guò)比較當(dāng)前元素和Nil來(lái)檢查是否達(dá)到列表末尾
val numbers =List(32,95,24,21,17,28,39,40,23,34)
var i=numbers //定義一個(gè)變量來(lái)進(jìn)行遍歷
while(i!=Nil){print(i.head+",");i=i.tail}
注:Nil實(shí)際上是List[Nothing] 的一個(gè)單例實(shí)例。
val l:List[Int] =List()
l == Nil
val m:List[String] =List("a")
m.head
m.tail==Nil
Cons操作符
- 使用Nil作為基礎(chǔ),并使用右結(jié)合的cons操作符::綁定元素,就可以構(gòu)建一個(gè)列表,而不必使用傳統(tǒng)的List(...) 格式
val numbers=1::2::3::Nil
for(i <- numbers) println(i)
列表算術(shù)算
var x1 =1::2::3::Nil //使用符號(hào)::
println(x1)
var x2 = List(1,2):::List(2,3)//合并兩個(gè)列表使用符號(hào):::
for(i <- x2) println(i)
println(List(1,2)++Set(3,4))//合并一個(gè)列表List和Set使用符號(hào)++
println(List(2,3,34,55,2,3).distinct)//取出List中的唯一的元素
println(List(2,3,34,55,2,3) drop 2)//刪除List中列表的前兩個(gè)元素
println(List(2,3,234,323,42,21) filter (_>18))//篩選出List列表中大于18的元素
println(List(1,2,3,4,5) partition (_<3)) //根據(jù)一個(gè)true/false 函數(shù)的結(jié)果,將元素分組為由兩個(gè)列表構(gòu)成的一個(gè)元組
println(List(List(1,2),List(3,4)).flatten)//將兩個(gè)列表扁平化變?yōu)橐粋€(gè)列表
println(List(1,2,3).reverse)//將列表進(jìn)行翻轉(zhuǎn)
println(Set(1,2,3) slice (1,2))//從列表的第一個(gè)索引直到第二個(gè)索引,但不包括第二個(gè)索引
List("apple","to") sortBy (_.size)//按給定函數(shù)返回的值對(duì)列表進(jìn)行排序
List("apple","to").sorted
List(2,3,5,7,11,13) take 3 //從列表中抽取前n個(gè)元素
映射列表
- 映射方法是指一個(gè)函數(shù),將它應(yīng)用于列表的每一個(gè)成員,再把結(jié)果收集到一個(gè)新列表。
- 以下為高階函數(shù)
//列表映射操作
List(0,1,0) collect {case 1=> "ok"} //使用一個(gè)偏函數(shù)轉(zhuǎn)換各元素,保留可應(yīng)用的元素
List("milk,tea","abc,dfsdf") flatMap (.split(",")) //使用一個(gè)給定函數(shù)轉(zhuǎn)換各個(gè)元素,將結(jié)果列表“扁平化”到這個(gè)列表中
List("milk","tea") map (_.toUpperCase) //使用給定函數(shù)轉(zhuǎn)換各個(gè)元素
List("apple","to") sortBy (_.size)//按給定函數(shù)返回的值對(duì)列表進(jìn)行排序
println(List(2,3,234,323,42,21) filter (_>18))//篩選出List列表中大于18的元素
println(List(1,2,3,4,5) partition (_<3)) //根據(jù)一個(gè)true/false 函數(shù)的結(jié)果,將元素分組為由兩個(gè)列表構(gòu)成的一個(gè)元組
歸約列表
- 歸約列表是處理集合的一個(gè)常見(jiàn)操作。將列表收縮為單個(gè)值。scala的集合操作支持?jǐn)?shù)學(xué)歸約操作(例如,查找一個(gè)列表的總和)和邏輯歸約操作(例如,確定一個(gè)列表是否包含某個(gè)給定的元素)
- 它們還支持通用的高階操作。
List(41,59,26).max //查找列表中的最大值
List(41,59,26).min //查找最小值
List(4,5,67).product //將列表中的元素乘積
List(11.3,23.5,7.2).sum //將列表中的元素相加
//下面的操作將列表歸約為一個(gè)布爾值。
List(24,39,18) contains 23
List(0,3,4) endsWith List(3,4)
List(5,6,7) exists (_<18)
List(0,4,3) startsWith List(0)
- 自己定義一個(gè)歸約的操作函數(shù)
def contains (x:Int,l:List[Int] ) :Boolean ={
var a =false
for(i <- l) {if(!a) a=(i==x) }
a
}
- 將以上函數(shù)推演歸納泛化到一般的情況
def reduceOp [A,B] (l:List[A],start:B)(f:(B,A) => B):B ={
var a =start
for(i<- l) a = f(a,i)
a
}
println(reduceOp[Int,Int](List(1,2,3),0)((x:Int,y:Int) => x+y ))
println(reduceOp[Int,Int](List(1,2,3),0)(su))
def su (x:Int,y:Int):Int ={x+y}
轉(zhuǎn)換集合
- 現(xiàn)在來(lái)考慮列表、集、映射之間的轉(zhuǎn)換
| 操作名 | 示例 | 描述 |
|---|---|---|
| mkString | List(24,99,104).mkString(",") | 使用給定分隔符講一個(gè)集合呈現(xiàn)為String |
| toBuffer | List('f','t').toBuffer | 將一個(gè)不可變的集合轉(zhuǎn)換為一個(gè)可變的集合 |
| toList | Map("a"-> 1,"b"-> 2).toList | 將一個(gè)集合轉(zhuǎn)換為一個(gè)List |
| toMap | Set(1->true,3-> true).toMap | 將一個(gè)2元元組的集合轉(zhuǎn)換為一個(gè)Map |
| toSet | List(2,5,5,3,2).toSet | 將一個(gè)集合轉(zhuǎn)換為一個(gè)Set |
| toString | List(2,5,5,3,2).toString | 將一個(gè)集合呈現(xiàn)為一個(gè)String,包括集合的類型 |
-
List(1,2,3,4,5,3,4,2).toSet.size和List(1,2,34,5,3,4,2).distinct.size均可以計(jì)算兩個(gè)列表中唯一元素的個(gè)數(shù) -
List(2,5,5,3,2).toBuffer.append(10)可以使用java中的Buffer類進(jìn)行可變集合中元素的增加
第7章 更多集合
可變集合
- 要修改集合,最直接的方法是利用一個(gè)可變的集合類型。見(jiàn)下表,列出了對(duì)應(yīng)表準(zhǔn)的不可變List、Map和Set類型的可變集合的可變集合類型。
| 不可變類型 | 可變類型 |
|---|---|
| collection.immutable.List | collection.mutable.Buffer |
| collection.immutable.Set | collection.mutable.Set |
| collection.immutable.Map | collection.mutable.Map |
- 盡管collection.immutable package 會(huì)自動(dòng)增加到scala的當(dāng)前命令空間,但不會(huì)增加collection.mutable package 。創(chuàng)建可變的集合時(shí),要確保包含類型的完整包名。
val nums=collection.mutable.Buffer(1)//創(chuàng)建一個(gè)可變的集合Buffer,其中只有元素1
for (i <- 2 to 10) nums+=i //集合中+=為添加元素
//或者使用nums.append(i)
println(nums.getClass)
println(nums)
//從一個(gè)空集合開(kāi)始添加元素
val nums1=collection.mutable.Buffer[Int]() //由于沒(méi)有默認(rèn)值,我們必須使用類型參數(shù)[Int],否則編譯失敗
for(i <- 1 to 10) nums1+=i
println(nums1)
- 構(gòu)建映射和集合的過(guò)程也類似。創(chuàng)建一個(gè)空的集合時(shí)候,只需要為新的集合指定類型的參數(shù),或者為一個(gè)新映射指定鍵和鍵值的類型參數(shù)
- 集合和映射類似,可以使用toList和toSet方法把這些可變的集合轉(zhuǎn)換為不可變的集合類型。
從不可變集合創(chuàng)建可變集合
- 除了直接創(chuàng)建可變的集合,還可以從不可變的集合轉(zhuǎn)換為可變的集合。如果開(kāi)始有一個(gè)不可變的集合,希望修改這個(gè)集合,或者希望寫List而不是 collection.mutable.Buffer()
- 不可變的集合List,Map,Set都可以使用toBuffer方法轉(zhuǎn)換為collection.mutable.Buffer 類型。對(duì)于列表,顯然這很自然。
//將一個(gè)不可變的映射轉(zhuǎn)換為可變的映射,然后再轉(zhuǎn)換回不可變的映射
val m=Map("AAPL" -> 579,"MSFT" -> 40)
val b=m.toBuffer
val n=b.toMap
val n1=b.toList
val n2=b.toSet
val b.append("AAPL" -> 579)
val n3=b.toSet
- Buffer 類型是一個(gè)很好的通用的可變集合,與List類似,不過(guò)還可以增加、刪除和替換內(nèi)容。由于它支持轉(zhuǎn)換方法,而且相應(yīng)的不可變類型提供了toBuffer 方法,使得Buffer類型成為處理可變數(shù)據(jù)的一個(gè)很有用的機(jī)制
使用集合構(gòu)建器
- Builder 是Buffer的一個(gè)簡(jiǎn)化形式,僅限于生成指定的集合類型,而且支持追加操作。
數(shù)組
Array是一個(gè)固定的可變索引集合。這不是正式意義上的集合,因?yàn)樗辉趕cala colloctions包里面。
Array類型實(shí)際上只是java數(shù)組的一個(gè)包裝器,另外還提供了一個(gè)高級(jí)特性,成為隱含類,是的它可以像序列一個(gè)樣使用。
scala提供Array類型來(lái)保證與jvm和java代碼的兼容性,另外用來(lái)作為索引集合的后備庫(kù),這使得數(shù)組很有用。
數(shù)組不同于List、set,它是一個(gè)可變的集合類,可以對(duì)數(shù)組中的元素進(jìn)行賦值操作。
val colors=Array("red","green","blue")
colors(0)="purple"
Seq和序列
- Seq是所有序列的根類型,包括類似List的鏈表和類似Vector的索引列表。
- 作為一個(gè)跟類型,Seq本身不能實(shí)例化,但是可以調(diào)用Seq創(chuàng)建List,這是創(chuàng)建List的一個(gè)快捷方式:
val inks =Seq('C','M','Y','K')
| 類型名 | 描述 |
|---|---|
| Seq | 所有序列的根類型,List()的快捷方式 |
| IndexedSeq | 索引序列的根類型,Vector()的快捷方式 |
| Range | 整數(shù)范圍。動(dòng)態(tài)生成數(shù)據(jù) |
| LinearSeq | 線性(鏈表)序列的根類型 |
| List | 元素的單鏈表 |
| Queue | 先進(jìn)先出列表 |
| Stack | 后進(jìn)先出列表 |
| Stream | 懶列表。訪問(wèn)元素時(shí)候才增加相應(yīng)元素 |
| String | 字符集合 |
Option
- Scala Option(選項(xiàng))類型用來(lái)表示一個(gè)值是可選的(有值或無(wú)值)。
- Option[T] 是一個(gè)類型為 T 的可選值的容器: 如果值存在, Option[T] 就是一個(gè) Some[T] ,如果不存在, Option[T] 就是對(duì)象 None 。
// 雖然 Scala 可以不定義變量的類型,不過(guò)為了清楚些,我還是
// 把他顯示的定義上了
val myMap: Map[String, String] = Map("key1" -> "value")
val value1: Option[String] = myMap.get("key1")
val value2: Option[String] = myMap.get("key2")
println(value1) // Some("value1")
println(value2) // None
- isEmpty() 方法
- 可以使用 isEmpty() 方法來(lái)檢測(cè)元組中的元素是否為 None,實(shí)例如下:
object Test {
def main(args: Array[String]) {
val a:Option[Int] = Some(5)
val b:Option[Int] = None
println("a.isEmpty: " + a.isEmpty )
println("b.isEmpty: " + b.isEmpty )
}
}
第8章 類
類
- 類是面向?qū)ο笳Z(yǔ)言的核心構(gòu)建,這是數(shù)據(jù)結(jié)構(gòu)與函數(shù)的組合。用值和變量定義的類可以根據(jù)需要實(shí)例化多次,每一個(gè)實(shí)例都可以用自己的輸入數(shù)據(jù)初始化。
- 類是對(duì)象的抽象,而對(duì)象是類的具體實(shí)例。類是抽象的,不占用內(nèi)存,而對(duì)象是具體的,占用存儲(chǔ)空間。類是用于創(chuàng)建對(duì)象的藍(lán)圖,它是一個(gè)定義包括在特定類型的對(duì)象中的方法和變量的軟件模板
class User
val u=new User
//新建一個(gè)類
- 現(xiàn)在會(huì)有一個(gè)類,會(huì)看到類名和一個(gè)十六進(jìn)制串。
import java.io._
class Point(xc:Int,yc:Int){
var x:Int=xc
var y:Int=yc
def move(dx:Int,dy:Int){
x=x+dx
y=y+dy
println("x的坐標(biāo)點(diǎn):"+x);
println("y的坐標(biāo)點(diǎn):"+y);
}
}
object Test{
def main(args:Arrary[String]){
val pt =new Point(10,20);
pt.move(10,10)
}
}
//scala中的類不聲明為public,一個(gè)scala源文件中可以由多個(gè)類
//以上實(shí)例的類定義了兩個(gè)變量x和y,一個(gè)方法move,方法沒(méi)有返回值
//scala的類定義可以有參數(shù),稱為類參數(shù),如上面的xc和yc,類參數(shù)在整個(gè)類中都可以訪問(wèn)
//接著我們可以使用new來(lái)實(shí)例化類,并訪問(wèn)類中的方法和變量。
scala繼承
- scala繼承一個(gè)基類跟java很相似,但我們需要注意以下幾點(diǎn):
- 重寫一個(gè)非抽象方法必須使用override修飾符
- 只有主構(gòu)造函數(shù)才可以往基類的構(gòu)造函數(shù)里寫參數(shù)
- 在子類中重寫超類的抽象方法時(shí),你不需要使用override關(guān)鍵字
- 一個(gè)類可以使用extends關(guān)鍵字?jǐn)U展最多一個(gè)其他類,另外可以用override關(guān)鍵字覆蓋所繼承方法的行為。類中的字段和方法可以用this關(guān)鍵字訪問(wèn),父類中的字段和方法可以用super關(guān)鍵字訪問(wèn)。如果一個(gè)方法需要訪問(wèn)其父類中的相應(yīng)方法,super關(guān)鍵字尤其有用。
class A {
def hi ="Hello from A"
override def toString =getClass.getName
}
class B extends A
class C extends B {override def hi = "hi C -> "+super.hi}
val hiA =new A().hi
val hiB =new B().hi
val hiC =new C().hi
import java.io._
class Point(val xc: Int, val yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
println ("x 的坐標(biāo)點(diǎn) : " + x);
println ("y 的坐標(biāo)點(diǎn) : " + y);
}
}
class Location( val xc: Int, val yc: Int,
val zc :Int) extends Point(xc, yc){
var z: Int = zc
//參數(shù)重寫中不需要加上override
def move(dx: Int, dy: Int, dz: Int) {
x = x + dx
y = y + dy
z = z + dz
println ("x 的坐標(biāo)點(diǎn) : " + x);
println ("y 的坐標(biāo)點(diǎn) : " + y);
println ("z 的坐標(biāo)點(diǎn) : " + z);
}
}
object Test {
def main(args: Array[String]) {
val loc = new Location(10, 20, 15);
// 移到一個(gè)新的位置
loc.move(10, 10, 5);
}
}
- 只有重寫方法函數(shù)需要加上修飾符override
- scala使用extends關(guān)鍵字來(lái)繼承一個(gè)類。實(shí)例中Location類繼承了Point類。Point稱為父類,Location稱為子類。
- 繼承會(huì)繼承父類的所有屬性和方法,scala只允許繼承一個(gè)父類
scala單例對(duì)象
- 在scala中,沒(méi)有static這個(gè)東西,但是它也為我們提供了單例模式的實(shí)現(xiàn)方法,那就是使用關(guān)鍵字object。scala中使用單例模式時(shí),除了定義的類之外,還要定義一個(gè)同名的object對(duì)象,它和類的區(qū)別就是,object對(duì)象不能帶參數(shù)。
- 當(dāng)單例對(duì)象與某個(gè)類共享同一個(gè)名稱時(shí),他被稱作是這個(gè)類的伴生對(duì)象:companion object。你必須在同一個(gè)源文件里定義類和它的伴生對(duì)象。類被稱為是這個(gè)單例對(duì)象的伴生類:companion class。類和它的伴生對(duì)象可以相互訪問(wèn)其私有成員。
import java.io._
class Point(val xc: Int, val yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
}
}
object Test {
def main(args: Array[String]) {
val point = new Point(10, 20)
printPoint
def printPoint{
println ("x 的坐標(biāo)點(diǎn) : " + point.x);
println ("y 的坐標(biāo)點(diǎn) : " + point.y);
}
}
}
定義類
- 類是對(duì)一個(gè)類型的定義,其中包含有核心類型和其他的字段(值和變量)。類還包含方法,也就是處理包含字段的一些函數(shù),另外還包含嵌套定義。
class <identifier> [extends <identifier>] [{fields,methods,and classes}]
類似表達(dá)式和函數(shù),類可以相互嵌套。嵌套類除了可以訪問(wèn)自己的字段和方法,還可以訪問(wèn)其父類的字段和方法。實(shí)例就是一個(gè)內(nèi)存分配,提供了類字段的存儲(chǔ)空間。這個(gè)動(dòng)作稱為實(shí)例化。可以使用new關(guān)鍵字按類名實(shí)例化一個(gè)類,可以加小括號(hào),也可以沒(méi)有。
更有用的是類可以由參數(shù),這是初始化類所用的字段和方法的輸入值,或者甚至可以作為類的字段。類參數(shù)是一個(gè)用逗號(hào)分隔的名字和類型的列表,形式與函數(shù)輸入?yún)?shù)相同。
//例子
class car(val make:String,var reserved :Boolean){
def reserve (r:Boolean) :Unit ={reserve =r}
}
val t =new car ("Toyota",false)
t.reserve(true)
println(s"My ${t.time} is now reserve?${t.reserve}")
val t2 =new car(reserved=false ,make ="Tsela")
class lotus(val color:String,reserved :Boolean) extends car ("lotus",reserved)
可以用標(biāo)準(zhǔn)中綴點(diǎn)記法訪問(wèn)一個(gè)類的字段和方法,實(shí)例與字段之間用一個(gè)點(diǎn)號(hào)分隔。
如果一個(gè)類擴(kuò)展了其他需要參數(shù)的類,則需要確保類定義中包含這些參數(shù)。extends關(guān)鍵字后面的類應(yīng)當(dāng)根據(jù)需要有自己的一組輸入?yún)?shù)。
可以為參數(shù)定義默認(rèn)值。
class car (val make:String,var reserved :Boolean =true ,val year :Int =2015)
{
override def toString =s"$yead $make ,reserved =$reserved "
}
val a =new car("Acura")
val l =new car("Lexus",year =2010)
val p =new car(reserved =false ,make ="Porsche")
重載方法
- 重載方法是為調(diào)用者提供更多選擇的一種策略。一個(gè)類可能有兩個(gè)或者多個(gè)名字和返回值相同的方法,但是輸入?yún)?shù)的設(shè)置不同。通過(guò)多個(gè)實(shí)現(xiàn)重載一個(gè)方法名,調(diào)用一個(gè)特定名字的方法時(shí)可以有多重選擇。
class Printer(msg:String){
def print(s:String) :Unit =println(s"$msg:$s")
def print(l:Seq[String]):Unit =print(l.mkString(","))
}
new Printer("Today's Reprot").print("Foggy"::"Rainy"::"Hot"::Nil)
- 重載是一個(gè)有用的特性,不過(guò)很多scala開(kāi)發(fā)人員更愿意使用默認(rèn)值參數(shù)而不是重載??梢栽诜椒ㄖ袨閰?shù)提供默認(rèn)值,而不是提供兩個(gè)方法(一個(gè)方法有參數(shù),另一個(gè)方法無(wú)參數(shù),無(wú)參數(shù)的方法會(huì)調(diào)用另一個(gè)有參數(shù)的方法并提供默認(rèn)值),這樣可以減少編寫不必要的代碼。
apply方法
- apply的方法有時(shí)是指作為一個(gè)默認(rèn)或一個(gè)注入方法,可以直接調(diào)用而不需要方法名。apply方法實(shí)際上是一個(gè)快捷方式,可以使用小括號(hào)出發(fā)功能而不需要方法名。
class Multiplier (factor:Int){
def apply(input:Int) =input* factor
}
val tripleMe =new Multiplier(3)
val tripled =tripleMe.apply(3)
- 將一個(gè)方法作為默認(rèn)方法有一個(gè)潛在的缺點(diǎn),這可能會(huì)讓代碼看起來(lái)有些奇怪。訪問(wèn)默認(rèn)方法應(yīng)當(dāng)很自然,比如列表的存取方法。類似列表的存取方法,只有在合理的情況下才應(yīng)當(dāng)使用apply方法。
包裝
- 包就是scala中的代碼組織系統(tǒng)。利用包,可以按照目錄使用點(diǎn)分隔路徑來(lái)組織scala代碼。如果在scala源文件前最前面使用package關(guān)鍵字,則聲明這個(gè)文件中的所有類都將包含在這個(gè)包中。
語(yǔ)法:為scala文件定義包
package <identifier>
- scala采用java標(biāo)準(zhǔn)來(lái)為包命名,包以組織或企業(yè)域的逆串開(kāi)頭,然后加上其他名構(gòu)成路徑。
- scala源文件要存儲(chǔ)在與包相匹配的目錄中。
com.netflix.utilities 包應(yīng)該存放在 com/netflix/utilities/DateUtilities.scala
//scala編譯器會(huì)把生成的.class文件存儲(chǔ)在與包匹配的目錄結(jié)構(gòu)中
訪問(wèn)包裝類
- 要訪問(wèn)其他包中的類,一種更高效的方法是將它們導(dǎo)入到當(dāng)前命名空間。這樣不需要包前綴也可以訪問(wèn)這個(gè)類。導(dǎo)入一個(gè)類時(shí)需要使用import關(guān)鍵字,后面是完整包和類名。
語(yǔ)法:導(dǎo)入一個(gè)包裝類
import <packages>.<class>
- 與java不同,代碼的任何地方都可以使用import語(yǔ)句
- scala還支持用下劃線操作符導(dǎo)入一個(gè)包的全部?jī)?nèi)容。導(dǎo)入后,這個(gè)包中的每一個(gè)類都會(huì)增加到命名空間。
import collection.mutable._
val b =new ArrayBuffer[String]
b.append("a","b","c")
- 從一個(gè)包導(dǎo)入所有類和子包可能有一個(gè)缺點(diǎn)。如果所導(dǎo)入的包中有一個(gè)類與命名空間中的一個(gè)類同名,那么就無(wú)法訪問(wèn)命名空間中國(guó)已有的那個(gè)類。
導(dǎo)入包組
- 除了導(dǎo)入整個(gè)包,另一種做法是使用導(dǎo)入組。利用這個(gè)特性,可以列出一組導(dǎo)入的類名,而不是一個(gè)完整的包。
語(yǔ)法:使用導(dǎo)入組
import <package>.{<class 1>[,<class 2>...]}
import collection.mutable.{Queue,ArrayBuffer}
val q =new Queue[Int]
val b =new ArraryBuffer[String]
導(dǎo)入包別名
語(yǔ)法:使用導(dǎo)入別名
import <package>.{<original name> => <alias>}
私密性控制
- protected 定義字段,不允許外部類訪問(wèn)。不過(guò),該字段仍可以由子類訪問(wèn)
- private ,僅限定義這個(gè)字段或方法的類可以訪問(wèn)。類之外的所有其他代碼甚至子類都不允許訪問(wèn)這個(gè)字段或者方法。
class User {protected val passwd =util.Random.nextString(10)}
附錄 代碼
import java.io._
object HelloWorld {
def main(args:Array[String]) :Unit ={//Unit類相當(dāng)于void返回值,為空
println("Hello World");
var x :String ="abc";
println(x);
println(x.getClass);
val y ="xcvxcv".r;
println(y.getClass());
println("A".hashCode);//返回一個(gè)值的散列碼
println((30/40).toString);
println((20.5).isInstanceOf[Float]);
val info = (5,"Korben",true)
println(info);
println(tran(20.5))
println()
println(round(3.7245));
print("\n")
val flag:Boolean =false;
val result:Boolean =(flag==false)
println(flag,result)
//重寫上面的Boolean類型的定義
val flag1 =false;
val result1 =(flag1==false)
println(flag1,result1)
println();
println(128.toChar);
println(128.toString);
println(128.toDouble);
println(128.toString.toDouble.toInt);
//正則表達(dá)式,需要加強(qiáng)學(xué)習(xí)
val zzbds="\\d{3}-\\d{3}-\\d{4}".r;
val input="Frank,123 Main,925-555-1943,95122";
println(zzbds findFirstIn input);
println((zzbds findAllIn input).mkString(","));
val status=600 ;
val message = status match {
case 200 => "ok"
case 400 => {println("ERROR - we called the service incorrectly")
println("error")
}
case 500 => {println("ERROR - the service encountered an error")
println("error")}
case other => {println("could not find"); -1}
}
println(message)
val res : String =null
res match {
case s if s!=null => println(s"Received '$s'")
case s => println("Error! Received a null res")//此處匹配s為匹配任意值
}
val xxx = for(x <- 1 to 7;if x % 2 !=0;if x >5 ) yield {s"Day $x:"}
// for (day <- xxx)println(day+",")
println(xxx)
//定義迭代器哨兵
val quote ="a,b,c"
for(t<- quote.split(",");if t!=null ;if t.size>0) println(t)
//多層迭代器
for(x<- 1 to 2 ;y<- 1 to 3){//兩個(gè)條件之間的分號(hào)還是必須要的
println(s"$x,$y")}
println()
println(f1(""))
println("f3函數(shù)的值為:"+f3(2.333))
println("f33函數(shù)的值為:"+f33(0))
println();
/* for(i <- 1 to 100)
{
if(i %5 ==0) println(i)
else print(i+",")
}
*/
for(i <- 1 to 100){
if(i %3 ==0 && i % 5!=0) { print("type,")}
else if(i %3 !=0 && i %5 ==0 ) {print ("safe,");println()}
else if(i %3 ==0 && i %5 ==0 ){ print ("typesafe,");println();}
else print(i+",")}
for(i <- 1 to 100){
var y = i match{
case x if(x%3==0 && x%5!=0) => "type"
case x if (x%3!=0 && x%5==0) => "safe"
case x if (x%3==0 && x%5==0) => "typesafe"
case other => i
}
if(i %5==0) println(y+",") else print(y+",")}//println函數(shù)是打印完之后再換行
println(safeTrim(" ab c "));
println(safeTrim(""));
println()
println(identity("adsfdasf").getClass)
println(identity(123434).getClass)
val d=2134;
println(d.compare(2135))
println(d compare 2135)
// println(area(10))
//mm(134134343444)
println(pow(2,30))
val yuanzu=(1234,"33",true)//元組
// if (yuanzu._1.isInstanceOf[Int]) {println(yuanzu._1)}
val yy =(yuanzu._1,yuanzu._2,yuanzu._3,yuanzu._1.toString,yuanzu._2.toString,yuanzu._3.toString)
println(yy)
// yuanzu.productIterator.foreach{k => {if(k.isInstanceOf[Int]) println(k)}}//元組遍歷
println(apply(layout,10))//復(fù)合函數(shù)
//使用匿名函數(shù)
val maxxx = (a:Int,b:Int) => if(a>b) a else b
println(maxxx(2,3))
/*
object HelloWorld {
def oncePerSecond(callback: () => Unit) { while (true) { callback(); Thread sleep 1000 } }
def main(args: Array[String]) { oncePerSecond(() => println("time flies like an arrow...")) }
}
*/
//高階函數(shù)
def safeStringOp(s:String,f:String => String) ={
if(s!=null) f(s) else s
}//定義復(fù)合函數(shù)
def reverser(s:String) = s.reverse//定義函數(shù)
println(safeStringOp(null,reverser))
println(safeStringOp("Ready",reverser))
val ff = (x:Int,y:Int) => x*y
def combination(x:Int,y:Int,f:(Int,Int)=> Int):Int= f(x,y)
println(combination(23,12,ff))
println(combination(23,12,(x:Int,y:Int) => x*y))
def tripleOp(a:Int ,b:Int,c:Int,f:(Int,Int,Int)=>Int )=a+b*f(a,b,c)-c
println(tripleOp(23,92,14,_*_+_))
//使用泛型函數(shù)來(lái)定義
def trip[A,B] (a:A,b:A,c:A,f:(A,A,A)=> B)=f(a,b,c)
println(trip[Int,Int](12,22,33,_+_+_))
println()
val maxium = (x:Int,y:Int) => if(x>y) x else y;
println("the max number is : "+maxium(2,3))
def yu (x:Int,y:Int,z:Int,maxium:(Int,Int)=> Int) = maxium(maxium(x,y),z)
println(yu(1,2,3,maxium))
println()
println(util.Random.nextInt)//返回一個(gè)隨機(jī)的整數(shù)
println(util.Random.nextDouble)//返回一個(gè)隨機(jī)的雙精度類型
println(util.Random.nextLong)//返回一個(gè)隨機(jī)的長(zhǎng)整型數(shù)
println()
//val x =util.Random.nextInt
//val y =util.Random.nextInt
def twomax (x:Int,y:Int,f:(Int,Int)=> Int) = f(x,y);
println(twomax(util.Random.nextInt(),util.Random.nextInt(),maxium))
def fzero[A](x:A)(f:A => Unit):A={f(x);x}
val zz = fzero[String]("abc")(println)
def square(m:Double):Double ={m*m}
//val sq : Double => Double = square
val sq = (x:Double) => x*x
println(sq(10.1))
def conditional[A] (x:A,p: A=> Boolean,q : A => Boolean )= {
if(p(x) && !q(x)) print("type,");
if(!p(x) && q(x)) println("safe")
if(p(x) && q(x)) println("typesafe")
if(!p(x) && !q(x)) print(x+",")
}
val px =(x:Int) => x %3==0
val qx =(x:Int) => x%5==0
for(i <- 1 to 100){conditional[Int](i,px,qx) }
/*def px (x:Int):Boolean = {
if(x>0) true else false
}*/
//val px = (x:Int) => if(x>0) true else false //匿名函數(shù)
//val fx = (x:Int) => x+1//匿名函數(shù)
/*def fx (x:Int):Int ={
x+1
}*/
// println(conditional[Int](10,px,fx))
val p_x = List(1,2,3)
//for (i <- p_x) {println(i)}
//for (i <- 1 to p_x.size) {println(i)}
val colors=List("red","green","blue","red","blue")
colors.foreach((c:String)=> println(c.length))
val sizes =colors.map((c:String)=>c.length)
val numbers =Set(32,95,24,21,17,17)
val numbers2 =List(32,95,24,21,17,17,28,29,30,31)
println("numbers的集合基數(shù)為:"+numbers.size)
println("numbers2的集合基數(shù)為:"+numbers2.size)
val total =numbers.reduce((a:Int,b:Int)=> a+b)
println(numbers+"Set為")
println(numbers2+"List為")
println(sizes)
println("集合中元素的和為:"+total)
/*Map類,鍵與鍵值
val colorMap =Map("red"-> 1, "blue"-> 2, "green" -> 3, "green" -> 4)//如果這樣會(huì)忽略green指向3的鍵和鍵值
val redRGB =colorMap("red")
val cyanRGB =colorMap("green") | colorMap("blue")
val hasWhite =colorMap.contains("white")
println(cyanRGB)
println(hasWhite)
for(i <- colorMap) {println(i)}
*/
var i =numbers2//將i設(shè)置為numbers的一個(gè)動(dòng)態(tài)變量
println(i.head)
println()
println(i.tail)
println()
while(! i.isEmpty){println(i.head+",");i=i.tail}
println()
println()
def visit(i:List[Int]):Unit ={
if(i.size>0) {print(i.head+","); visit(i.tail) }
if(i.size==1) {print(i.head); visit(i.tail) }
}//遞歸遍歷一個(gè)List
visit(numbers2)
println()
val num3 =List(32,95,24,21,17,28,39,40,23,34)
var i2=num3 //定義一個(gè)變量來(lái)進(jìn)行遍歷
while(i2!=Nil){print(i2.head+",");i2=i2.tail}
println()
println()
val n3=1::2::3::Nil
println(n3)
for(i <- n3) println(i)
def factors (x:Int):List[Int] ={
val y = for(i <- 2 to x-1 if(x%i==0))yield{ i } //返回值為vector類型
return y.toList
}
println(factors(16))
println(List(15,11,9).flatMap(factors))
def fir[A] (items:List[A],count:Int):List[A]={
val y=for(i <- 0 to count-1)yield {
items(i)
}
return y.toList
}//輸出一個(gè)列表的前count個(gè)數(shù)據(jù)
println(fir(List("a","b","c"),2))
def longstring (x:List[String]):List[String] ={//返回字符串長(zhǎng)度最長(zhǎng)的字符串
var max=0
for(i <- 0 to x.size-1) {
if(x(i).length>= max) max=x(i).length
}//找出最大值
val index =for(i <- 0 to x.size-1 if(x(i).length == max))yield{
i
}//找出最大值的下標(biāo)
val S = for(i <- index.toList)yield{
x(i)
}//提取出最大值
return S.toList
}
println(longstring(List("a","abc","ac","adsf","adsfa","rer","addfd")))
def revse[A](x:List[A]):List[A]={
val y = for(i <- 0 to x.size-1 )yield {
x(x.size-1-i)
}
return y.toList
}
println(revse(List("a","abc","ac","adsf","adsfa","rer","addfd")))
//def pati (x:List[String]):(List[String],List[String])
def pati (x:String) :Boolean={
var y=true
for(i <- 0 to x.size-1 if(x(i)!=x(x.size-1-i)))
{
y=false
}
return y
}
println(List("a","abc","ac","adsf","adsfa","rer","addfd").partition(pati))
///////////////可變集合////////////////////
println("可變集合:")
val nums=collection.mutable.Buffer(1)//創(chuàng)建一個(gè)可變的集合Buffer,其中只有元素1
for (i <- 2 to 10) nums.append(i)
println(nums.getClass)
println(nums)
//從一個(gè)空集合開(kāi)始添加元素
val nums1=collection.mutable.Buffer[Int]() //由于沒(méi)有默認(rèn)值,我們必須使用類型參數(shù)[Int],否則編譯失敗
for(i <- 1 to 10) nums1+=i
println(nums1)
val x1 = Array[Int](10,2,3,10)
val x2=x1.toBuffer
for(i <- x1) println(i)
println(x2.getClass)
println(x2)
x2.append(200)
println(x2)
val a:Option[Int] = Some(5)
val b:Option[Int] = None
println("a.isEmpty: " + a.isEmpty )
println("b.isEmpty: " + b.isEmpty )
val xyz = List(1,2,3).toBuffer
println(xyz.getClass)
println(xyz)
//面向?qū)ο缶幊?val pt =new Point(10,20);
pt.move(10,10)
val loc =new Location(10,20,15);
loc.move(10,10,5)
println();
val users =List(new User("Shoto"),new User("Art3mis"),new User("abc"));
println(users)
var x12 =new User("xycz");
println(x12)
println(x12.greet)//面向?qū)ο缶幊?
val sizess=users.map(_.name.size);//.name方法返回一個(gè)函數(shù)的名字
val names=users.map(_.name);//.name方法返回一個(gè)函數(shù)的名字
println(sizess)
println(names)
val hiA =new A().hi
val hiB =new B().hi
val hiC =new C().hi
println(hiA)
println(hiB)
println(hiC)
println()
val x3 = List(10,20,30).reduce(plus)
println(x3)
val x4 =List(10,20,30,20,10).foldLeft(false)((x:Boolean,y:Int) => if(x) x else y==30)//判斷一個(gè)列表中是否包含某一個(gè)元素
println(x4)
class Printer(msg:String){
def print(s:String) :Unit =println(s"$msg:$s")
def print(l:Seq[String]):Unit =print(l.mkString(","))
}
new Printer("Today's Reprot").print("Foggy"::"Rainy"::"Hot"::Nil)
class multiplier(factor:Int){
def apply(input:Int)=input*factor
}
println()
val trip0 =new multiplier(3)//新建一個(gè)對(duì)象
val trip1=trip0.apply(10)//執(zhí)行方法
val trip2=trip0(10)//隱藏了方法
println(trip1)
println(trip2)
import java.util.Date//導(dǎo)入java包
val dd =new Date
println(dd)
}
//////////////////////主函數(shù)結(jié)束////////////////////////////////////
def plus (x:Int,y:Int):Int ={
return x+y
}
def apply(f:Int => String,v:Int) =f(v)
def layout[A](x:A):String ={"["+x.toString+"]"}
//定義函數(shù)////////////////////////////////////////////////
def identity[A](a: A):A=a //該函數(shù)設(shè)置無(wú)論輸入什么類型的參數(shù)都返回輸入值
def safeTrim(s:String):String ={ //該函數(shù)功能為去掉字符串兩端的空格
if(s=="") return null //判斷字符串是否是為空的,如果為空則返回null
s.trim()
}
def ff (xx: String): String ={
if(xx !="") return xx else return "n/a";
}
def f1 (xx: String): String ={
var y = xx match {
case "" => "n/a";
case other => xx;
}
return y
}
def f3 (q : Double ): String = {
if(q>0) return "greater" ;
else if(q==0) return "same" ;
else return "less";
}
def f33(q: Double ): String ={
var y:String=""
y = q match {
case x1 if(x1>0 || x1==0) => "greater"
case x3 if (x3<0) => "less"
}
return y
}
//實(shí)現(xiàn)將攝氏溫度轉(zhuǎn)換為華氏溫度
def tran (xx:Double ):Int= {
var yy :Double =0;
yy=(xx*9/5)+32;
return yy.toInt;
}
//定義一個(gè)冪指數(shù)函數(shù)
def power(x:Int,n:Int):Long={
if(n>=1) x*power(x,n-1)
else 1
}
//實(shí)現(xiàn)保留兩位小數(shù)的四舍五入
def round (a :Double ): String ={
var x:Double =0;
var x1:Int =0;
var x2:Int =0;
var x3:Int =0;
var x4:Int =0;
x=a*1000;
x1=x.toInt/1000;
x2=x.toInt%(x1*1000)/100;
x3=x.toInt%(x1*1000+x2*100)/10;
x4=x.toInt%(x1*1000+x2*100+x3*10);
if(x4>=5){
x3=x3+1}
var u:String =( x1+0.1*x2+0.01*x3).toString;
return s"You owe $$$u";
}
//第4章練習(xí)
def area(x:Double): Double ={
return 3.14*x*x
}
def mm(x:Long):Unit={
val day = x / (3600*24*1000);
val hour = x%(3600*24*1000)/(1000*3600);
val min = x%(3600*24*1000)%(1000*3600)/(60*1000)
val sec = x%(3600*24*1000)%(1000*3600)%(60*1000)/1000
println(s"day=${day},hour=${hour},min=${min},sec=${sec}")
}
def pow(x:Int,y:Int):Long ={ //定義一個(gè)冪指數(shù)函數(shù)
var pro =1;
for (i <- 1 to y)
{
pro=pro*x
}
return pro
}
}//靜態(tài)類結(jié)束
class Point(xc:Int,yc:Int){
var x:Int=xc
var y:Int=yc
def move(dx:Int,dy:Int){
x=x+dx
y=y+dy
println("x的坐標(biāo)點(diǎn):"+x);
println("y的坐標(biāo)點(diǎn):"+y);
}
}
class Location( val xc :Int, val yc :Int,val zc:Int) extends Point(xc,yc){
var z:Int =zc
def move (dx:Int,dy:Int,dz:Int){
x=x+dx;
y=y+dy;
z=z+dz;
println("x的坐標(biāo)點(diǎn):"+x);
println("y的坐標(biāo)點(diǎn):"+y);
println("z的坐標(biāo)點(diǎn):"+z);
}
}
class User(val name:String){
def greet:String =s"Hello from $name"
override def toString =s"User($name)"
}
class A {
def hi ="Hello from A"
override def toString =getClass.getName
}
class B extends A
class C extends B {override def hi = "hi C -> "+super.hi}