Scala快速入門系列:聲明變數、控制結構與函數、常用數組操作
Scala快速入門-1-聲明變數
背景
- 因為Spark是由Scala開發的,所以在開發Spark應用程序之前要對Scala語言學習。雖然Spark也支持Java、Python語言,但是作為一名Java程序猿,還是決定要學習Scala哈。
- Scala是運行在JVM上一門語言。開發效率非常高、語法豐富簡潔,三兩行Scala代碼能搞定Java要寫的一大坨代碼。
- Scala的語法糖太甜~~
Scala特性
面向對象特性
- Scala是一種純面向對象的語言,每個值都是對象。
函數式編程
- Scala也是一種函數式語言,其函數也能當成值來使用。Scala提供了輕量級的語法用以定義匿名函數,支持高階函數,允許嵌套多層函數,並支持柯里化。Scala的case class及其內置的模式匹配相當於函數式編程語言中常用的代數類型。
- 可以利用Scala的模式匹配,編寫類似正則表達式的代碼處理數據。
並發性
- Scala使用Actor作為其並發模型,Actor是類似線程的實體,通過「郵箱」發收消息。Actor可以復用線程,因此可以在程序中可以使用數百萬個Actor,而線程只能創建數千個。在2.10之後的版本中,使用Akka作為其默認Actor實現。
主要內容
- 聲明變數、常用類型
- 控制結構(條件、循環、for)、函數
- 常用數組操作
- 類與對象
- 繼承與特質
- 集合
- 模式匹配和樣例類
聲明變數、常用類型
- scala代碼會被編譯成位元組碼,然後交給Java虛擬機執行。
- 不強制指定變數的類型,編譯器會推斷出來。
scala> 8 * 5nres0: Int = 40n
- val定義的值無法改變它的內容。在Scala中,鼓勵使用val。
scala> val answer = 8 * 5nanswer: Int = 40nnscala> answer = 10n<console>:8: error: reassignment to valn answer = 10n
- 如果要聲明其值可變的變數,用var。
scala> var counter = 0ncounter: Int = 0nnscala> counter = 10ncounter: Int = 10n
- 變數或函數的類型總是寫在變數或函數名稱後面,與Java的習慣不同。
scala> val greeting : String = "Hello"ngreeting: String = Hellon
- 不需要使用分號最後,僅當同一行代碼中存在多條語句時才需要分號隔開。
- 常用的數據類型與Java一樣,Byte、Char、Short、Int、Long、Float、Double及Boolean,這些都是類。
- 在基本類型和包裝類型之間的轉換是Scala編譯器的工作。
- +-*/%等操作符實際上是方法。
- 對於BigInt和BigDecimal對象,可以以常規的方式使用數學操作符(但在Java中同樣的操作要寫成x.multiply(x))。
scala> val x : BigInt = 123nx: BigInt = 123nnscala> x * xnres1: scala.math.BigInt = 15129n
- 不帶參數的Scala方法通常不使用圓括弧,一般沒有參數且不改變當前對象的方法不帶圓括弧。
Scala快速入門-2-控制結構與函數
背景
- 表達式有值,語句執行動作。
- Scala中,幾乎所有構造出來的語法結構都有值,不像Java中把表達式和語句(if語句)分為兩類。
- 在這裡if表示式有值。
- 代碼塊也有值,最後一個表達式就是值。
- 語句中,分號不是必需的。
- 函數式中不使用return。
條件表達式
- 在Scala中if/else表達式有值,這個值就是在if或else之後的表達式的值。
scala> var x = 10nx: Int = 10nnscala> val r = if (x > 0) 1 else -1nr: Int = 1nnscala> var x = 0nx: Int = 0nnscala> val r = if (x > 0) 1 else -1nr: Int = -1n
- 可能if沒有輸出值,但在Scala中,每個表達式都有某種值。
scala> var x = 0nx: Int = 0nnscala> val r = if (x > 0) 1nr: AnyVal = ()n
塊表達式和賦值
- 在Scala中{}塊包含一系列表達式,其結果也是一個表達式。塊中最後一個表達式的值就是塊的值。
- 對於某個val的初始化需要分多步完成的情況很實用。
val dis = {val dx = x - x0; val dy = y - y0; sqrt(dx * dx + dy * dy)}n
循環
- while與Java中的循環一樣。
while(n > 0) {ntr = r * nntn -= 1n}n
- Scala沒有for(初始化; 檢查變數是否滿足; 更新變數)的結構。
for(i <- 1 to n) {ntr = r * in}n
- 1 to n 表達式表示:返回數據1到n(包含)的區間。
- 1 until n 表達式表示:返回數據1到n(不包含)的區間。
增強for循環和for推導式
- 可以以 變數<-表達式的形式提供多個生成器,用分號將他們隔開
scala> for(i <- 1 to 3; j <- 1 to 3) print ((10 * i + j) + " ")n11 12 13 21 22 23 31 32 33n
- 每個生成器都可以帶一個守衛,以if開頭的Boolean表達式 (if前並沒有分號)
scala> for(i <- 1 to 3; j <- 1 to 3 if i != j) print((10 * i + j) + " ")n12 13 21 23 31 32n
- for推導式:for循環的循環以yield開始,則該循環會構造出一個集合,每次迭代生成集合中的一個值
scala> for(i <- 1 to 10) yield i % 3nres2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)n
函數
- 函數定義:需要給出函數名、參數和函數體,格式如下
def abs(x: Double) = if (x >= 0) x else -xn
- 必須給出所有參數的類型
- 遞歸函數必須指定返回值類型
def fac(n: Int) : Int = if(n <= 0) 1 else n * fac(n - 1)n
- 不需要
return
語句 - 有
=
等號連接函數體 - 默認參數和帶名參數
scala> def decorate(str: String, left: String = "[", right: String = "]") = left + str + rightndecorate: (str: String, left: String, right: String)Stringnnscala> decorate("Hello World")nres3: String = [Hello World]nnscala> decorate("Hello World", "<", ">")nres4: String = <Hello World>n
- 也可以在提供參數值時指定參數名,這樣就可與函數定義參數列表的順序不一致
scala> decorate(left = "<<", str = "Hello Scala", right = ">>")nres5: String = <<Hello Scala>>n
- 可以混用未命名參數和帶名參數,只要未命名的參數排在前面即可
scala> decorate("Hello Spark", right = "]<<")nres6: String = [Hello Spark]<<nn相當於nnscala> decorate("Hello Spark", "[", "]<<")n
- 實現一個可以接受可變長參數列表的函數
scala> def sum(args: Int*) = {n | var result = 0n | for (arg <- args) result += argn | resultn | }nsum: (args: Int*)Intnnscala> val s = sum(1, 3, 5, 7)ns: Int = 16n
- 可以使用
_*
將一個整數區間轉換成參數序列
直接使用會拋出如下錯誤:nnscala> val ss = sum(1 to 5)n<console>:8: error: type mismatch;n found : scala.collection.immutable.Range.Inclusiven required: Intn val ss = sum(1 to 5)n nscala> val ss = sum(1 to 5: _*)nss: Int = 15n
- 如果函數體包含在花括弧當中,但沒有前面的
=
號,返回類型是Unit,這樣的函數被稱做過程。過程不返回值,調用它僅僅是為了它的副作用。 - 當val被聲明為lazy時,它的始始化將被推遲,直到首次對它取值。
lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkStringnn可以故意把文件名寫錯,試一下在初始化語句被執行的時候會不會報錯(只有訪問words時才提示文件未找到) n
Scala快速入門-3-常用數組操作
知識點
- 長度固定使用Array,長度有變化使用ArrayBuffer
- 提供初始值時不要使用new
- 用()來訪問元素
- for(elem <- arr)遍曆元素
- for(elem <- arr if …) yield …將原數組轉為新數組
定長數組
- 10個整數的數組,所有元素初始為0
scala> val nums = new Array[Int](10)nnums: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)n
- 10個元素的字元中數組,所有元素初始化為null
scala> val str = new Array[String](10)nstr: Array[String] = Array(null, null, null, null, null, null, null, null, null, null)n
- 提供初始值就不需要new,長度為2的Array[String],類型是推斷出來的
scala> val str1 = Array("Hello", "Scala")nstr1: Array[String] = Array(Hello, Scala)n
- 使用()來訪問元素
scala> val s = str1(0)ns: String = Hellon
變長數組
- 與Java中ArrayList功能等效的數據結構ArrayBuffer
- 初始化一個空的可變長數組,準備存入整數
scala> import scala.collection.mutable.ArrayBuffernimport scala.collection.mutable.ArrayBuffernnscala> val b = ArrayBuffer[Int]()nb: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()n
- 用+=在尾添加元素或多個用括弧包都來的元素
scala> b += 1nres0: b.type = ArrayBuffer(1)nnscala> b += (1, 2, 3)nres1: b.type = ArrayBuffer(1, 1, 2, 3)n
- 用++=操作符追加任何集合
scala> b ++= Array(6, 8, 9)nres2: b.type = ArrayBuffer(1, 1, 2, 3, 6, 8, 9)n
- 移除最後2個元素
scala> b.trimEnd(2)nnscala> bnres4: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 2, 3, 6)n
- 可在任意位置插入或移除元素(不高效,所有在那個位置後面的元素都必須被平移)
// 在下標2之前插入nscala> b.insert(2, 4)nnscala> bnres6: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 4, 2, 3, 6)nn// 在下標2之前插入多個元素nscala> b.insert(2, 4, 5)nnscala> bnres8: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 4, 5, 4, 2, 3, 6)n
- 定長數組與變長數據轉換
// 轉成定長數組nscala> b.toArraynres9: Array[Int] = Array(1, 1, 4, 5, 4, 2, 3, 6)nnn// 轉成變長數組nscala> b.toBuffernres10: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 1, 4, 5, 4, 2, 3, 6)n
遍曆數組
// 使用下標訪問nscala> for (i <- 0 until b.length)n | println(i + ":" + b(i))n0:1n1:1n2:4n3:5n4:4n5:2n6:3n7:6nn// 不使用下標nscala> for(elem <- b)n | println(elem)n1n1n4n5n4n2n3n6n
數組轉換
- for推導式,從一個數組轉換,生成一個全新的數組
scala> val a = Array(2, 3, 5, 7)na: Array[Int] = Array(2, 3, 5, 7)nnscala> val res = for(elem <- a) yield 2 * elemnres: Array[Int] = Array(4, 6, 10, 14)nnscala> anres13: Array[Int] = Array(2, 3, 5, 7)n
- for推導式,從一個ArrayBuffer轉換,生成一個全新的ArrayBuffer
scala> a.toBuffernres14: scala.collection.mutable.Buffer[Int] = ArrayBuffer(2, 3, 5, 7)nnscala> val res = for(elem <- res14) yield 2 * elemnres: scala.collection.mutable.Buffer[Int] = ArrayBuffer(4, 6, 10, 14)n
作者:Yezhiwei
鏈接:
- Scala快速入門-1-聲明變數|Yezhiwei的博客 | Yezhiwei Blog
- Scala快速入門-2-控制結構|Yezhiwei的博客 | Yezhiwei Blog
- Scala快速入門-3-常用數組操作|Yezhiwei的博客 | Yezhiwei Blog
聲明:本文來源於網路,版權歸作者所有,轉載請註明,若有什麼問題,請聯繫我們,謝謝!
推薦閱讀:
※Spark 2017歐洲技術峰會摘要(Spark 生態體系分類)
※如何利用spark快速計算笛卡爾積?
※Scala 究竟好在那裡?
※如何學好Scala?請給出一條科學的時間線
※矽谷之路38:深入淺出Spark(三)什麼是Standalone