scala學(xué)習(xí)筆記

scala學(xué)習(xí)筆記


第2章 變量和數(shù)據(jù)類型

基本數(shù)據(jù)

  1. scala的核心數(shù)據(jù)為四種 :字面量、值、變量、類型
  2. 值使用val來(lái)定義、變量使用var來(lái)定義 val x: Int =20 var x: Int =30,定義值和變量
  3. 在scala中,值優(yōu)先于變量,這是因?yàn)榭梢詾樵创a帶來(lái)穩(wěn)定性和可預(yù)測(cè)性。

數(shù)值型類型

  1. Byte
  2. Short
  3. Int
  4. Long
  5. Float
  6. Double

scala不允許從較高等級(jí)類型自動(dòng)轉(zhuǎn)換到較低等級(jí)類型,但是可以使用toType方法手動(dòng)完成類型間的轉(zhuǎn)換,所有數(shù)值型都有這樣一個(gè)方法。例如:toInt\toString\toDouble、、

字符串

注:雙引號(hào)為字符串String,單引號(hào)為字符Char

  1. 與數(shù)值型類似,String類型也支持使用數(shù)學(xué)運(yùn)算符。"string"+"abc"、"string2"*2等等

  2. 可以使用三重引號(hào)創(chuàng)建多行String。多行字符串是字面量,所以如果其中使用了反斜杠,不要認(rèn)為是一個(gè)特殊的轉(zhuǎn)義字符。

  3. 字符串內(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)

  1. 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 
  1. 嵌套迭代器
  • 嵌套迭代器是增加到一個(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")}
  1. 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ù)

  1. 語(yǔ)法 : 定義無(wú)輸入的函數(shù) def <identifier> = <expression>
def hi ="hi"
  1. 語(yǔ)法: 定義函數(shù)時(shí)指定返回類型 def <identifier>: <type>=<expression>

  2. 定義函數(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è)箭頭從輸入類型指向輸出類型
  1. 將函數(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
  1. 使用通配符為函數(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ù)替換為通配符下劃線。可以在以下情況使用:
  1. 函數(shù)的顯示類型在字面量之外定義
  2. 函數(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ù)

列表、集合映射

  1. 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ù)
  1. 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ù)的元素。
  1. 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一樣的操作

  1. 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.sizeList(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):
  1. 重寫一個(gè)非抽象方法必須使用override修飾符
  2. 只有主構(gòu)造函數(shù)才可以往基類的構(gòu)造函數(shù)里寫參數(shù)
  3. 在子類中重寫超類的抽象方法時(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}



最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容