在Java或者C++中,咱們把表達式和語句看作兩種不一樣的東西。表達式有值,而語句執行動做。java
在Scala中,幾乎全部構造出來的語法結構都是有值的。這個特性使得程序更加的精簡,也更易讀。app
scala> val x = 1 x: Int = 1 scala> val res = if(x == 1) 1 else 0 res: Int = 1 scala> var res = if(x == 1) "hello" else 3 res: Any = hello
Scala的語句無需添加相似Java和C++的分號;
表示結尾,編譯器會自動判斷。固然,若是單行下存在多個語句,那麼則須要用分號隔開前面的n-1個語句:框架
if ( x > 1) { r = r * n; n = n -1 }
一、塊表達式函數
{ }
表示一系列表達式,其結果也是一個表達式。塊中最後一個表達式的值就是塊的值。this
val distance = { val dx = x - x0; val dy = y - y0; sqrt(dx *dx + dy * dy)}
能夠看到,這樣的語法能夠很乾淨的讓dx、dy等對外部不可見了。scala
二、賦值語句code
一個以賦值語句結束的塊,返回的是Unit類型的值。所以,相似於這樣的操做可能和java中的不同遞歸
x = y = 1
顯然 x 的值爲y = 1
,即(),也是Unit類型。前面咱們提到過一次性初始化的方式element
scala> val x, y = 1; x: Int = 1 y: Int = 1
一、普通輸出文檔
scala> print("I love you.") I love you. scala> println("I love you too.") I love you too. 換行
二、字符串插值輸出
scala> val name = "akuya" name: String = akuya scala> print(f"I love $name!") I love akuya!
格式化的字符串是Scala類庫定義的三個字符串插值器之一。經過不一樣的前綴採起不一樣的輸出策略:
\n
會原樣輸出三、控制檯讀取
可使用scala.io.StdIn的readLine方法從控制檯讀取一行輸入。
一、while
和java的使用一致
二、for
和java的使用有所區別,其使用方式以下所示
for(i <- 表達式)
例如
scala> for(i <- 1 to 10) println(i) 1 2 3 ...
能夠看到中間的特殊符號 <-
表示讓變量i遍歷(<-)右邊的表達式的全部值。至於這個遍歷具體的執行方式,則取決於後面的表達式的類型。對於集合而言,他會讓i依次取得區間中的每一個值。例如:
scala> for(i <- "abcde") print(s" $i") a b c d e
生成器: >-
後面的表達式。
守衛:每一個生成器均可以帶上守衛,一個以if開頭的Boolean表達式
scala> for(i <- 1 to 3; j <- 1 to 3 if(i != j)) print(f"(i=$i,j=$j) ") (i=1,j=2) (i=1,j=3) (i=2,j=1) (i=2,j=3) (i=3,j=1) (i=3,j=2)
注意在if以前沒有分號,多個生成器之間須要分號
定義:在循環中對變量賦值,從而引入變量。
scala> for(i <- 1 to 3; j <- 1 to 3;home = i) print(f"(i=$i,j=$j,home=$home) ") (i=1,j=1,home=1) (i=1,j=2,home=1) (i=1,j=3,home=1) (i=2,j=1,home=2) (i=2,j=2,home=2) (i=2,j=3,home=2) (i=3,j=1,home=3) (i=3,j=2,home=3) (i=3,j=3,home=3)
其中home = i
就是一個定義。
yield:若是for循環的循環體以yield關鍵字開始,則該循環會構造出一個集合,每次迭代生成集合中的一個值:
scala> val vec = for (i <- 1 to 20) yield i % 2 vec: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0)
注意與類的方法進行區分。
在Java中函數只能用類的靜態方法來模擬。
定義函數
def abs(x:Double) = if(x >= 0) x else -x
若是函數不是遞歸的,就不須要指定返回值類型。
一樣,塊中的最後一個表達式的值就是函數的值。
若是是遞歸函數,則須要定義返回值類型
def fac(n: Int): Int = {...}
調用某些函數時能夠沒必要顯式的給出全部參數值,對於這些函數咱們可使用默認參數。
def decorate(str: String, left: String = "[", right: String = "]"){...} // 調用 decorate("hello") // 調用2 decorate("hello","(",")")
def sum(args: Int*) = {...}
Scala對於不返回值的函數有特殊的表示法。若是函數體包含在花括號中但沒有前面的=
,那麼返回類型就是Unit。這樣的函數被稱爲過程。
// 省略了=號 def box(s: String) {...}
固然,既然返回值是Unit類型,那麼過程也能夠用以下的方法定義
def box(s: String): Unit = {...}
當val被生命爲lazy時,他的初始化將會被推遲,直到咱們首次對他取值。很像Linq或者Spark RDD等許多數據處理框架的惰性原理。
scala> lazy val words = scala.io.Source.fromFile("/noexist.file") words: scala.io.BufferedSource = <lazy> scala> words.toString java.io.FileNotFoundException: \noexist.file (系統找不到指定的文件。)
能夠看到,即使咱們一開始的words取的是一個不存在的文件,也沒有當即報錯,而是在咱們對words進行取值以後纔出現了錯誤。
能夠把懶值理解爲val和def的中間狀態。
Scala和java不同,不支持「受檢異常」。
throws表達式有特殊的類型Nothing。
若是一個分支的類型是Nothing,那麼if/else
表達式的類型就是另外一個分支的類型。
捕獲異常的語法採用的是模式匹配語法。
一、一個數字若是爲正數,則他的signum爲1;若是是負數,則signum爲-1,;若是是0,則signum爲0.編寫一個函數來計算這個值。
package com.zhaoyi.c2 object Practice2 { def signum(x: Int): Int = { if(x > 0){ 1 } else if( x == 0){ 0 }else{ -1 } } def main(args: Array[String]): Unit = { println("signum(100) = " + signum(100)); println("signum(0) = " + signum(0)); println("signum(-100) = " + signum(-100)); // 或者使用系統函數 println("use system signum(10) = " + BigInt(10).signum); } }
輸出結果:
signum(100) = 1 signum(0) = 0 signum(-100) = -1 use system signum(10) = 1
二、一個空的塊表達式{}
的值是什麼?類型是什麼?
scala> var s = {} s: Unit = ()
Unit表示無值,和其餘語言中void等同。用做不返回任何結果的方法的結果類型。Unit只有一個實例值,寫成()。
三、指出在scala中何種狀況下賦值語句 x = y = 1
是合法的。
顯然,只須要有「須要x的值爲()」的時候,這樣的需求是合法的。
四、針對下列Java循環編寫一個Scala版的程序。
for(int i = 10;i>=0;i--){ System.out.println(i); }
scala版:
for(i <- 1 to 10 reverse) println(i)
五、編寫一個過程countdown(n: Int)
,打印從n到0的數字。
def answer5(n: Int): Unit ={ for(i <- 0 to n reverse){ print(i + " ") } }
六、編寫一個for循環,計算字符串中全部字母的Unicode代碼的乘積。
def answer6(str: String): Long = { var res: Long = 1 for(c <- str){ res *= c.toLong } println(s"$str count value is: " + res) res } def main(args: Array[String]): Unit = { answer6("Hello") }
七、一樣是問題6,但此次不容許使用循環語句。
查找到
def foreach(f: (A) ⇒ Unit): Unit [use case] Applies a function f to all elements of this string.
所以能夠考慮使用foreach方法計算。
def answer7(str: String): Long = { var res: Long = 1 str.foreach(c => res *= c.toLong) println(s"$str count value is: " + res) res } def main(args: Array[String]): Unit = { answer7("Hello") }
八、編寫一個函數product(s: String),計算前面練習中提到的乘積。
def product(str: String): Long = { var res: Long = 1 str.foreach(c => res *= c.toLong) println(s"$str count value is: " + res) res }
九、把前一個練習中的函數改造爲遞歸函數
def answer9(str: String): Long = { if(str.length == 1){ str(0).toLong }else{ // 選擇第0個元素,返回除了第0個元素的其餘元素 str(0).toLong * answer9(str.drop(1)) } } def main(args: Array[String]): Unit = { val ans = answer9("Hello") print(ans) }
其中Doc文檔:
// 返回除了前n個節點的元素 def drop(n: Int): String Selects all elements except first n ones. // 並無用到此方法 def take(n: Int): String Selects first n elements. // 默認方法 apply def apply(index: Int): Char Return element at index n
十、編寫函數計算$x^n$,其中n是整數,使用以下的遞歸定義
def answer10(x: Double, n: Int): Double = { if(n == 0) 1 else if (n > 0 && n % 2 == 0) answer10(x,n/2) * answer10(x,n/2) else if (n > 0 && n % 2 == 1) x * answer10(x,n - 1) else 1 / answer10(x, -n) } def main(args: Array[String]): Unit = { val ans = answer10(2,2) print(ans) // 4.0 }