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

TAG:Scala | Spark | 快学Scala书籍 |