有趣的 Scala 語言:簡潔的 Scala 語法(scala語言入門)
一、scala開發(fā)環(huán)境
搭建Scala 開發(fā)環(huán)境,一是在IntelliJ IDEA 上安裝Scala 插件和安裝Scala SDK,具體操作步驟可以參考Scala專欄文章。
二是通過Scala RELP(Read-Eval-Print Loop)交互式環(huán)境,該交互式環(huán)境適合代碼簡單調(diào)試,不太適合進(jìn)行應(yīng)用開發(fā)。
二、變量和函數(shù)
定義變量時沒有指定變量類型。這是否意味著 Scala 是和 Python 或者 Ruby 一樣的動態(tài)類型語言呢?恰恰相反,Scala 是嚴(yán)格意義上的靜態(tài)類型語言,由于其采用了先進(jìn)的類型推斷(Type Inference)技術(shù),程序員不需要在寫程序時顯式指定類型,編譯器會根據(jù)上下文推斷出類型信息。比如變量 x被賦值為 0,0 是一個整型,所以 x的類型被推斷出為整型。當(dāng)然,Scala 語言也允許顯示指定類型,如變量 x1,y1的定義。一般情況下,我們應(yīng)盡量使用 Scala 提供的類型推斷系統(tǒng)使代碼看上去更加簡潔。
另一個發(fā)現(xiàn)是程序語句結(jié)尾沒有分號,這也是 Scala 中約定俗成的編程習(xí)慣。大多數(shù)情況下分號都是可省的,如果你需要將兩條語句寫在同一行,則需要用分號分開它們。
函數(shù)的定義也非常簡單,使用關(guān)鍵字 def,后跟函數(shù)名和參數(shù)列表,如果不是遞歸函數(shù)可以選擇省略函數(shù)返回類型。Scala 還支持定義匿名函數(shù),匿名函數(shù)由參數(shù)列表,箭頭連接符和函數(shù)體組成。函數(shù)在 Scala 中屬于一級對象,它可以作為參數(shù)傳遞給其他函數(shù),可以作為另一個函數(shù)的返回值,或者賦給一個變量。在下面的示例代碼中,定義的匿名函數(shù)被賦給變量 cube。匿名函數(shù)使用起來非常方便,比如 List對象中的一些方法需要傳入一個簡單的函數(shù)作為參數(shù),我們當(dāng)然可以定義一個函數(shù),然后再傳給 List對象中的方法,但使用匿名函數(shù),程序看上去更加簡潔。
// 定義函數(shù)
def square(x: Int): Int = x * x
// 如果不是遞歸函數(shù),函數(shù)返回類型可省略
def sum_of_square(x: Int, y: Int) = square(x) square(y)
sum_of_square(2, 3)
// 定義匿名函數(shù)
val cube = (x: Int) => x * x *x
cube(3)
// 使用匿名函數(shù),返回列表中的正數(shù)
List(-2, -1, 0, 1, 2, 3).filter(x => x > 0)
讓我們再來和 Java 中對應(yīng)的函數(shù)定義語法比較一下。首先,函數(shù)體沒有像 Java 那樣放在 {}里。Scala 中的一條語句其實(shí)是一個表達(dá)式,函數(shù)的執(zhí)行過程就是對函數(shù)體內(nèi)的表達(dá)式的求值過程,最后一條表達(dá)式的值就是函數(shù)的返回值。如果函數(shù)體只包含一條表達(dá)式,則可以省略 {}。其次,沒有顯示的 return語句,最后一條表達(dá)式的值會自動返回給函數(shù)的調(diào)用者。
和 Java 不同,在 Scala 中,函數(shù)內(nèi)部還可以定義其他函數(shù)。比如上面的程序中,如果用戶只對 sum_of_square 函數(shù)感興趣,則我們可以將 square 函數(shù)定義為內(nèi)部函數(shù),實(shí)現(xiàn)細(xì)節(jié)的隱藏。
定義內(nèi)部函數(shù):
三、流程控制語句
復(fù)雜一點(diǎn)的程序離不開流程控制語句,Scala 提供了用于條件判斷的 if else和表示循環(huán)的 while。和 Java 中對應(yīng)的條件判斷語句不同,Scala 中的 if else是一個表達(dá)式,根據(jù)條件的不同返回相應(yīng)分支上的值。比如下面例子中求絕對值的程序,由于 Scala 中的 if else是一個表達(dá)式,所以不用像 Java 那樣顯式使用 return返回相應(yīng)的值。
使用 if else 表達(dá)式:
def abs(n: Int): Int = if (n > 0) n else -n
和 Java 一樣,Scala 提供了用于循環(huán)的 while 語句,在下面的例子中,我們將借助 while 循環(huán)為整數(shù)列表求和。
使用 while 為列表求和:
def sum(xs: List[Int]) = {
var total = 0
var index = 0
while (index < xs.size) {
total = xs(index)
index = 1
}
total
}
上述程序是習(xí)慣了 Java 或 C 的程序員想到的第一方案,但仔細(xì)觀察會發(fā)現(xiàn)有幾個問題:首先,使用了 var定義變量,我們在前面說過,盡量避免使用 var。其次,這個程序太長了,第一次拿到這個程序的人需要對著程序仔細(xì)端詳一會:程序首先定義了兩個變量,并將其初始化為 0,然后在 index小于列表長度時執(zhí)行循環(huán),在循環(huán)體中,累加列表中的元素,并將 index加 1,最后返回最終的累加值。直到這時,這個人才意識到這個程序是對一個數(shù)列求和。
讓我們換個角度,嘗試用遞歸的方式去思考這個問題,對一個數(shù)列的求和問題可以簡化為該數(shù)列的第一個元素加上由后續(xù)元素組成的數(shù)列的和,依此類推,直到后續(xù)元素組成的數(shù)列為空返回 0。具體程序如下,使用遞歸,原來需要 9 行實(shí)現(xiàn)的程序現(xiàn)在只需要兩行,而且程序邏輯看起來更清晰,更易懂。
使用遞歸對數(shù)列求和:
//xs.head 返回列表里的頭元素,即第一個元素
//xs.tail 返回除頭元素外的剩余元素組成的列表
def sum1(xs: List[Int]): Int = if (xs.isEmpty) 0 else xs.head sum1(xs.tail)
有沒有更簡便的方式呢?答案是肯定的,我們可以使用列表內(nèi)置的一些方法達(dá)到同樣的效果:
上述使用了規(guī)約操作。
規(guī)約操作是對容器的元素進(jìn)行兩兩運(yùn)算,將其規(guī)約為一個值。最常見的規(guī)約方式使 reduce,它接受一個二元函數(shù) f 作為參數(shù),首先將 f 作用在某兩個元素上并返回一個值,然后再將 f 作用在上一個返回值和容器的下一個元素上,再返回一個值,依次類推,最后容器中的所有值會被規(guī)約為一個值。
list map (_.toString) reduce((x,y)=>s"f($x,$y)")
上面這行代碼:先通過 map 操作將List[Int] 轉(zhuǎn)化成 List[String],也就是把列表中的每個元素從 Int 類型轉(zhuǎn)換成 String 類型,然后對這個字符串進(jìn)行自定義規(guī)約,語句的執(zhí)行結(jié)果清楚地展示了 reduce的過程。
事實(shí)上,List 已經(jīng)為我們提供了 sum 方法,在實(shí)際應(yīng)用中,我們應(yīng)該使用該方法,而不是自己定義一個。作者只是希望通過上述例子,讓大家意識到 Scala 雖然提供了用于循環(huán)的 while 語句,但大多數(shù)情況下,我們有其他更簡便的方式能夠達(dá)到同樣的效果。
四、如何運(yùn)行 Scala 程序?
在運(yùn)行方式上,Scala 又一次體現(xiàn)出了它的靈活性。它可以被當(dāng)作一種腳本語言執(zhí)行,也可以像 Java 一樣,作為應(yīng)用程序執(zhí)行。
作為腳本執(zhí)行:
我們可以將 Scala 表達(dá)式寫在一個文件里,比如 Hello.scala。在命令行中直接輸入 scala Hello.scala就可得到程序運(yùn)行結(jié)果。
Hello.scala 代碼:
println("Hello Rickie!")
作為應(yīng)用程序執(zhí)行:
作為應(yīng)用程序執(zhí)行時,我們需要在一個單例對象中定義入口函數(shù) main,經(jīng)過編譯后就可以執(zhí)行該應(yīng)用程序了。
object HelloRickie {
def main(args: Array[String]): Unit = {
println("Hello Rickie!")
}
}
Scala 還提供了一個更簡便的方式,直接繼承另一個對象 App,無需定義 main方法,編譯即可運(yùn)行。
五、結(jié)束語
本文為大家介紹了 Scala 的基本語法,相比 Java,Scala 的語法更加簡潔,比如 Scala 的類型推斷可以省略程序中絕大多數(shù)的類型聲明,短小精悍的匿名函數(shù)可以方便的在函數(shù)之間傳遞,還有各種在 Scala 社區(qū)約定俗成的習(xí)慣,比如省略的分號以及函數(shù)體只有一條表達(dá)式時的花括號,這一切都幫助程序員寫出更簡潔,更優(yōu)雅的程序。