Scala學習筆記(二)表達式和函數

筆記的整理主要針對Scala對比Java的新特性;shell

 

一、if表達式數組

if表達式是有結果返回的。app

val a= if (5>2) 「你好」 else 1函數

a的值爲if表達式返回值爲 「你好」優化

 

二、while表達式scala

while表達式是沒有返回值的(返回值爲 Unit),在scala中避免使用,一般都須要與var結合使用對象

 

三、for表達式blog

枚舉集合遍歷遞歸

val a = Array(1,2,3,4,5,6)get

for (i <- a) println(i)

以上for表達式遍歷的語法成爲發生器,不只僅只是適合Array也適合其它集合類;

for表達式中 to 與 until的區別:to包含上限,until不包含上限;

遍歷過濾

for (i <- a if i>3) println(i)

if i>3稱爲發生器i <- a 的守衛,主要用於對發生器產生的數據進行過濾;

嵌套枚舉

for (i <- 0 to 5 if i>1 ;j <- 5 to 10 if j<9 ) println("i:"+i+",j:"+j)

這裏有兩個發生器,每一個發生器都帶有一個守衛。

執行的順序爲:先對將 i 賦值爲一個合法的值(即知足區間在0~5之間且i大於1),而後依次完成對 j 合法值(即知足區間在5~10之間且 j小於9)的全部遍歷,而後對 i 進行下一個合法值的遍歷賦值,再重複對 j合法值的全部遍歷,後面的過程以此類推;

產生新集合結果

val a = for (i <- 0 to 10 if i>5) yield i

image

for-yield語法:for (表達式) yield{循環體}

 

四、本地函數

特色:在方法中定義的方法,且本地方法僅在包含它代碼塊中可見(相似局部變量);

 

五、頭等函數

把函數當值傳遞(如同變量),函數字變量被編譯進類,並在運行期實例化爲函數值。所以函數自變量與值的區別在於函數自變量存在於源碼,而函數值作爲對象存在於運行期(相似類與對象之間的關係);

函數自變量的構成包含括號、參數列別、右箭頭和函數體。如:(x:Int) => x+1 ; 右箭頭左邊爲括號很參數,右邊爲函數體

image 

當編譯器能推斷出參數類型時,參數類型能夠省略:

var v = Array(1,2,3,4,5)

v.foreach(x => println(x+1))

 

六、佔位符

把下畫線當作一個或更多參數的佔位符,只要每一個參數在函數字面量內僅出現一次。

例如:

scala> v.filter(_ > 0)
res0: Array[Int] = Array(1, 3, 7)

 

七、部分應用函數

用單個下劃線替換整個參數列表;

例如:

scala> def add (a:Int,b:Int) = a+b
add: (a: Int, b: Int)Int

scala> val sum = add _
sum: (Int, Int) => Int = <function2>

scala> sum(1,2)
res1: Int = 3

sum變量指向一個函數值對象,該函數值依照部分應用函數表達式add _,自動產生的類的一個實例,編譯器產生的類有一個apply方法帶兩個參數,參數的個數有add _表達式缺乏的參數數量肯定;

另外一種表現形式(轉換函數值):

scala> def add(a:Int,b:Int) = a+b
add: (a: Int, b: Int)Int

scala> val sum = add(2,_:Int)
sum: Int => Int = <function1>

scala> sum(2)
res2: Int = 4

注意:一個省略全部參數的偏程序表達式(如:add _),且在代碼的某個地方正須要一個函數,能夠去掉下劃線使表達式更簡潔。如:scala> v.foreach(println)

 

八、可變參數

容許客戶向函數傳入可變長度參數列表,若想要標註一個重複參數,可在參數的類型以後放一個星號。

例1:

scala> def echo (args:String*)=
     | for (arg <- args)println(arg)
echo: (args: String*)Unit

scala> echo()

scala> echo("hello","world")
hello
world

例2:

scala> var arr = Array("hello","world","chenx")
arr: Array[String] = Array(hello, world, chenx)

scala> def echo (args:String*)=for(arg <- args) println(arg)
echo: (args: String*)Unit

scala> echo(arr:_*)

重複參數的類型是聲明參數類型的數組,當參數類型爲一個合適類型的數組時,須要在數組參數後添加一個冒號和一個_*符號。

 

九、尾遞歸

方法的最後一個動做是調用本身的函數稱爲尾遞歸。Scala對尾遞歸的狀況進行了優化,比基於循環的實現更優美很簡明,由於無需付出任何運行期開銷,且遞歸必須是直接的。

注:-g:notailcalls 參數傳遞給scala shell 或者scalac編譯器,可用來跟蹤堆棧信息。

 

十、柯里化

對柯里化的理解能夠爲根據方法參數的個數,對方法進行拆解,如:def f(a:Int,b:Int)=a+b 轉換爲 def f(a:Int)(b:Int)=a+b

例1:

scala> def f(a:Int)(b:Int)=a+b
f: (a: Int)(b: Int)Int

scala> val t = f(1)_
t: Int => Int = <function1>

scala> t(2)
res0: Int = 3

例2:

scala> def f(a:Int)=(b:Int)=>a+b
f: (a: Int)Int => Int

scala> val t=f(1)
t: Int => Int = <function1>

scala> t(2)
res1: Int = 3

對比兩個例子有必定的不一樣,例1使用佔位符號獲取f的第二函數,由f(1)_返回,例2運用的是方法f返回一個函數值並進行的下一步調用;

 

十一、控制抽象

在傳入一個參數時,用花括號替代小括號的機制。當參數爲函數字面量時讓方法的調用更像控制抽象;

例:

scala> def f(msg:String)(op:String => Unit){
     | op(msg)}
f: (msg: String)(op: String => Unit)Unit

scala> f("123456"){println(_)}
123456

該例中是將def f(msg:String,op:String => Unit)柯里化爲def f(msg:String)(op:String => Unit),使其在調用函數字面量時能使用花括號,最後的println(_)也能夠替換爲 t => println(t),其中t爲參數可任意命名;

十二、傳名參數應用

做用:在匿名函數基礎上爲函數命名;

例:

scala> def f(op:() => Boolean){
     | if (op())
     | println("OK")
     | else
     | println("ERROR")
     | }
f: (op: () => Boolean)Unit

scala> f(() => 5>3)
OK

  • def f(op:() => Boolean)可轉換爲def f(op: => Boolean)並在在調用時可簡化爲f(5>3)便可;
  • def f(op:() => Boolean)與def f(op:Boolean)的區別,op:() => Boolean表示一個函數字面量,而op:Boolean表示參數Boolean二者有本質上的區別;
相關文章
相關標籤/搜索