Scala是一門有趣且實用的語言,它以JVM位目標環境,將面向對象和函數式編程有機地結合起來,帶來獨特的編程體驗。本文主要整理《快學Scala》中的初級A1部分,適用於Scala的初級應用開發學習。轉載請註明博客原文地址:http://blog.tomgou.xyz/kuai-xue-scalachu...html
解壓scala安裝包到任意目錄:java
$ cd /home/tom $ tar -xzvf scala-2.10.6.tgz $ sudo vim /etc/profile
在/etc/profile
文件的末尾添加環境變量:程序員
export SCALA_HOME=/home/tom//scala-2.10.6 export PATH=$SCALA_HOME/bin:$PATH
保存並更新/etc/profile
:算法
$ source /etc/profil
查看是否成功:shell
$ scala -version
創建一個簡單的scala程序scalatest.scala
:編程
object scalatest { def main(args:Array[String]){ def box(s:String){ var border = "-" * s.length + "--\n" println(border + "|" + s +"|\n" + border) } box("Hello Tom!") } }
編譯程序:vim
$ scalac scalatest.scala
執行程序:api
$ scala scalatest
獲得結果:數組
------------ |Hello Tom!| ------------
Scala解釋器讀到一個表達式,對它求值,將其打印,接着再繼續讀下一個表達式。這個過程被稱爲讀取-求值-打印-循環,即REPL。bash
scala> 8 * 5 + 2 res0: Int = 42
從技術上講,scala程序並非一個解釋器。實際發生的過程是,你輸入的內容被快速地編譯成字節碼,而後這段字節碼交由Java虛擬機執行。
REPL在同一時間只能看到一行代碼。
在REPL粘貼成塊代碼,須要鍵入:paste
,粘貼代碼塊,而後按下Ctrl+D。
以val定義常量,以var定義變量:
val answer = 8 * 5 + 2 var counter = 0 counter = 1
在Scala中,咱們鼓勵使用val。同時,你不須要給出值或者變量的類型,這個信息能夠從你初始化它的表達式中判斷出來。必要時,可指定類型,如:
val greeting: String = null
在Scala中,無需分號,僅當同一行代碼中存在多條語句時才用分號分開。
和Java同樣,Scala有7種數據類型:
Byte Char Short Int Long Float Double Boolean
跟Java不一樣的是,這些類型是類。你能夠對數字執行方法,如:
1.toString() //產出字符串"1" 1.to(5) //產出Range(1,2,3,4,5)
Scala用底層的java.lang.String類來表示字符串,不過經過StringOps類給字符串追加了上百種操做,好比:
"Hello".intersect("World") //輸出"lo"
Scala還提供了RichInt,RichDouble,RichChar等,提供了Int,Double,Char不具有的便捷方法。好比1.to(10)
中,Int值1首先被轉換成RichInt,而後調用to方法。
+-*/%等操做符其實是方法,好比a+b
是以下方法a.+(b)
的簡寫。
一般你能夠用a 方法 b
來簡寫方法a.方法(b)
。好比1.to(5)
能夠寫成1 to 5
。
Scala沒有提供++
和--
操做符,須要使用+=1
或-=1
,如counter += 1
。
在Scala中使用數學函數比Java簡單,你不須要從某個類調用它的靜態方法。
sqrt(2) pow(2, 4)//16.0 min(3, Pi)//3.0
這些數學函數在scala.math
包中定義,能夠經過如下語句引入:
import scala.math._ //在Scala中,_字符是通配符,相似Java中的*
引入以scala.開頭的包時,能夠省去scala前綴。
不帶參數的Scala方法一般不使用圓括號,如:
"Hello".distinct
"Hello"(4)//將產出'o'
"Hello"(4)
是以下方法的簡寫:
"Hello".apply(4)
()
操做符能夠做爲apply方法的重載形式,好比說將字符串或數字轉換成BigInt對象的apply方法,BigInt("123")
是BigInt.apply("123")
的簡寫,Array(1,4,9)
返回一個數組,用的就是Array伴生對象的apply方法。
能夠在http://www.scala-lang.org/api在線瀏覽Scaladoc。
類名旁的O和C分別連接到對應的類(C)和伴生對象(O)
標記爲implicit的方法對應的是自動隱式轉換
方法能夠以函數做爲參數
Scala中的if/else表達式有值,這個值就是if或else後的值,如:
val s = if (x > 0) 1 else -1
上式將if/else表達式的值賦值給常量。還能夠這樣寫:
if (x > 0) s = 1 else s = -1
不過第一種寫法更好,第二種寫法中,s必須是變量var。
以下是混合類型的條件表達式:
if (x > 0) "positive" else -1
一個分支是String,另外一個是Int,它們的公共超類型叫作Any。
當if語句沒有輸出值時,引入了Unit類,寫作()
。以下:
if (x > 0) 1 else ()
()
能夠當作是表示「無有用值」的佔位符。
Scala與JavaScript等腳本語言相似,行尾位置不須要分號。
若是你在寫較長的語句,須要分兩行來寫的話,確保第一行以一個不能用做語句結尾的符號結尾,如:
s = s0 + (v - v0) * t + 0.5 * (a - a0) * t * t
Scala程序員傾向使用Kernighan & Ritchie風格的花括號:
if (n > 0) { r = r * n n -= 1 }
在Scala中,{}
塊包含一系列表達式。塊中最後一個表達式的值就是塊的值。如:
val distance = {val dx=x-x0;val dy=y-y0;sqrt(dx*dx+dy*dy)}
賦值動做自己是沒有值的,是Unit類型的。一個以賦值語句結束的塊,好比:{r=r*n;n-=1}
的值是Unit類型的。x=y=1//別這樣
中,x被賦的值是Unit類型的。
打印:
print("hello") println(42) //打印內容後會追加一個換行符
格式化字符串的printf:
printf(" %s is %d years old.\n","Fred",42)
用readLine函數從控制檯讀取一行輸入:
val name = readLine("Your name: ")
Scala擁有與Java和C++相同的while和do循環,如:
while(n > 0){ r = r * n n -= 1 }
for循環使用for(i <- 表達式)
這樣的語法結構,讓變量i遍歷表達式的全部值,如:
for(i <- 1 to n) r = r * i
遍歷字符串或數組時,一般須要使用0到n-1的區間,until方法返回一個不包含上限的區間:
val s = "hello" var sum = 0 for(i <- 0 until s.length) sum += s(i)
或:
var sum = 0 for(ch <- 0 "hello") sum += ch
Scala沒有提供break或continue語句來退出循環,咱們能夠:
1.使用Boolean型的控制變量。
2.嵌套函數,函數中return。
3.使用Breaks對象中的break方法。
多個生成器:
for(i <- 1 to 3; j <- 1 to 3) print((10*i+j)+" ") //打印11 12 13 21 22 23 31 32 33
生成器可帶守衛(注意:if前無分號):
for(i <- 1 to 3; j <- 1 to 3 if i!=j) print((10*i+j)+" ") //打印12 13 21 23 31 32
for推導式(yield),循環會構造出一個集合,集合與第一個生成器的類型兼容:
for(i <- 1 to 10) yield i%3 //生成Vector(1,2,0,1,2,0,1,2,0,1) for(c <- "Hello"; i <- 0 to 1) yield (c+i).toChar //生成"HIeflmlmop" for(i <- 0 to 1; c <- "Hel") yield (c+i).toChar //生成Vector('H','e','l','I','f','m')
定義函數須要名稱,參數,函數體:
def abs(x:Double) = if(x >= 0) x else -x
函數可使用代碼塊,塊中最後一個表達式的值是函數的返回值:
def fac(n: Int) = { var r = 1 for(i <- 1 to n) r = r *i r }
對於遞歸函數,必須指明返回類型:
def fac(n:Int): Int = if(n <= 0) 1 else n * fac(n - 1)
過程就是不返回值的函數,返回類型爲Unit。定義時能夠略去'=',如:
def box(s:String){ var border = "-" * s.length + "--\n" println(border + "|" + s +"|\n" + border) }
也能夠顯示聲明:
def box(s:String): Unit = { var border = "-" * s.length + "--\n" println(border + "|" + s +"|\n" + border) }
val nums = new Array[Int](10) //10個整數的數組,全部元素初始化爲0 val a = new Array[String](10) //10個元素的字符串數組,全部元素初始化爲null val s = Array("Hello","World") //已提供初始值時不須要new s(0) = "Goodbye" //使用()來訪問元素
在JVM中,Scala的Array以Java數組實現,好比Array(2,3,5,7,11)
在JVM中就是一個Int[]
。
對於長度按需變化的數組,Java有ArrayList,C++有vector,Scala中的等效數據結構爲ArrayBuffer。
val b = ArrayBuffer[Int]() //或val b = new ArrayBuffer[Int] b += 1 //用+=在尾端添加元素 b += (1,2,3,5) //添加多個元素 b ++= Array(8,13,21) //用++=追加任何集合 b.trimEnd(5) //移除最後5個元素
有時須要構建一個Array,但不知道最終要裝多少元素,能夠先構建一個數組緩衝ArrayBuffer,而後轉化爲Array:
b.toArray
同時,你可使用insert
和remove
來插入或移除元素。
使用for循環:
for (i <- 0 until a.length) println(i + ": " + a(i))
until是RichInt
類的方法,0 until 10
其實是0.until(10)
,若是想讓區間是每兩個元素一跳,能夠這樣寫0 until (a.length, 2)
,若是從數組尾端開始,能夠這樣寫(0 until a.length).reverse
。
若是在循環體中不須要用到數組下標,咱們能夠直接訪問數組元素:
for(elem <- a) println(elem)
在Scala,從一個數組或變長數組出發,以某種方式對它進行轉換是很簡單的,這些轉換動做不會修改原始數組,而是產生一個全新的數組。
好比使用for yield推倒式:
val a = Array(2,3,5,7,11) val result = for (elem <- a) yield 2 * elem //result是Array(4,6,10,14,22)
當你遍歷一個集合,只想處理那些知足特定條件的元素時,你能夠加入守衛,好比這裏對每一個偶數元素翻倍,丟到奇數元素:
for (elem <- a if elem % 2 == 0) yield 2 * elem
另外一種作法:
a.filter(_ % 2 == 0).map(2 * _)
求最小和最大min
和max
求和(數值類型):
Array(1,7,2,9).sum //19
排序sorted
:
val b = ArrayBuffer(1,7,2,9) val bSorted = b.sorted //ArrayBuffer(1,2,7,9)
排序(提供比較函數)sortWwith
:
val bDescending = b.sortWith(_ > _) //ArrayBuffer(9,7,2,1)
顯示mkString
:
b.mkString(" and ") //"1 and 7 and 2 and 9"
顯示toString
:
b.toString //"ArrayBuffer(1,7,2,9)"
多維數組是經過數組的數組來實現的,舉例來講,Double
的二維數組類型爲Array[Array[Double]]
,構造時能夠用ofDim方法:
val matrix = Array.ofDim[Double](3,4) //3*4
訪問元素時使用兩對圓括號:
matrix(row)(column) = 42
參考書籍: