Scala入門

保留字

保留字 說明
abstract 抽象聲明
case match表達式中的case子句;定義一個case類
catch 捕捉拋出的異常
class 聲明一個類
def 定義一個方法
do 用於do...while循環
else 與if配對的else語句
extends 表示接下來的class或trait是所聲明的class或trait的父類型
false Boolean的false值
final 用於class或trait,表示不能派生子類型;用於類型成員,則表示派生的class或trait不能覆寫它
for for循環
forSome 用在已存在的類型聲明中,限制其可以使用的具體類型
if if語句
implicit 使得方法或變量值能夠被用於隱含轉換;將方法參數標記爲可選的,只要在調用該方法時,做用域內有類型匹配的候選對象,就會使用該對象做爲參數
import 將一個或多個類型抑或類型的成員導入到當前做用域
lazy 推遲val變量的賦值
match 用於類型匹配語句
new 建立類的一個實例
null 還沒有被賦值的引用變量的值
object 用於單例聲明,單例是隻用一個實例的類
override 當原始成員未被聲明爲final時,用override覆寫類型中的一個具體成員
package 聲明包的做用域
private 限制某個聲明的可見性
protected 限制某個聲明的可見性
requires 停用,之前用於子類型
return 從函數返回
sealed 用於父類型,要求全部派生的子類型必須在同一個源文件中聲明
super 相似this,單表示父類型
this 對象指向自身的引用;輔助構造函數的方法名
throw 拋出異常
trait 這是一個混入模塊,對類的實例添加額外的狀態和行爲;也能夠用於聲明而不實現方法.相似java的interface
try 將可能拋出異常的代碼塊包圍起來
true Boolean的true值
type 聲明類型
val 聲明一個"只讀"變量
var 聲明一個可讀可寫的變量
while 用於while循環
with 表示所聲明的類或實例化的對象包括後面的trait
yield 在for循環中返回元素,這些元素會構成一個序列
_ (下劃線) 佔位符,使用imort,函數字面量中
: 分隔標識符和類型註解
= 賦值
=> 在函數字面量中分隔參數列表與函數體
<- 在for循環中的生成表達式
<: 在參數化類型和抽象類型聲明中,用於限制容許的類型
<% 在參數化類型和抽象類型的view bound生命中
>: 在參數化類型和抽象類型生命中,用於限制容許的類型
# 在類型注入中使用
@ 註解

Scala不存在breakcontinue關鍵字shell

分號

  • 分號是表達式之間的間隔
  • 當一行結束時,Scala就認爲表達式結束了,除非它能夠判斷出該表達式還沒有結束

變量聲明

  • Scala容許聲明變量是可變的仍是不可變的
  • 聲明不可變變量使用val
  • 聲明可變變量使用var
// 聲明不可變變量,這裏只是array不可再更改,可是數組內容能夠更改
val array:Array[String] = new Array(5)
// 可變
var price: Double = 1.1

Range

  • 生成從某個起點到某個終點的一個數字序列
  • 支持Int, Long, Float, Double, Char, BigInt, BigDecimal
  • 使用to包括區間上限
  • 使用until不包括區間上限
  • 使用by設置步長
scala> 1 to 5
res2: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)

scala> 1 until 5
res3: scala.collection.immutable.Range = Range(1, 2, 3, 4)
scala> 1 to 10 by 3
res0: scala.collection.immutable.Range = Range(1, 4, 7, 10)

scala> 0.1f to 5.3f by 1.0f
res1: scala.collection.immutable.NumericRange[Float] = NumericRange(0.1, 1.1, 2.1, 3.1, 4.1, 5.1)

scala> 'a' to 'g'
res2: scala.collection.immutable.NumericRange.Inclusive[Char] = NumericRange(a, b, c, d, e, f, g)

scala> BigInt(1) to BigInt(5) by 2
res3: scala.collection.immutable.NumericRange[BigInt] = NumericRange(1, 3, 5)

偏函數

  • 不處理全部可能的輸入,只處理那些能與至少一個case語句匹配的輸入
  • 在偏函數中,只能使用case語句
  • 整個函數必須用花括號包圍
  • 若是偏函數被調用,而函數的輸入卻與全部語句都不匹配,系統就會拋出一個MatchError運行時錯誤
  • 使用isDefineAt方法測試特定輸入是否與偏函數匹配
  • 偏函數鏈式鏈接: pf1 orElse pf2 orElse pf3 ... 只有全部偏函數都不匹配,纔會拋出MatchError

示例

代碼

// file: pf.scala
var pf1: PartialFunction[Any, String] = { case s: String => "YES"}
var pf2: PartialFunction[Any, String] = { case d: Double => "YES"}

val pf = pf1 orElse pf2

def tryPF(x: Any, f: PartialFunction[Any, String]): String =
    try {f(x).toString} catch {case _: MatchError => "ERROR!"}

def d(x: Any, f: PartialFunction[Any,String]) =
    f.isDefinedAt(x).toString

println("      |   pf1 - String |   pf2 - Double  |   pf - All")
println("x     | def?  | pf1(x) | def?   | pf2(x) | def?  |  pf(x)")
println("+" * 50)
List("str", 3.14, 10) foreach {
    x => printf("%-5s | %-5s | %-6s | %-6s | %-6s | %-5s | %-6s\n", x.toString, d(x, pf1), tryPF(x, pf1),
        d(x, pf2), tryPF(x, pf2), d(x, pf), tryPF(x, pf))
}

運行

scala pf.scala數組

運行結果

|   pf1 - String |   pf2 - Double  |   pf - All
x     | def?  | pf1(x) | def?   | pf2(x) | def?  |  pf(x)
++++++++++++++++++++++++++++++++++++++++++++++++++
str   | true  | YES    | false  | ERROR! | true  | YES   
3.14  | false | ERROR! | true   | YES    | true  | YES   
10    | false | ERROR! | false  | ERROR! | false | ERROR!

方法聲明

方法默認值和命名參數列表

  • 能夠爲方法參數提供默認值
  • 調用方法時能夠只提供部分參數值,能夠只傳入指定參數

示例

代碼

case class Point(x: Double = 0.0, y: Double = 0.0) {
    def shift(deltax: Double = 0.0, deltay: Double = 0.0) = 
        copy (x + deltax, y + deltay)
}

val p1 = new Point(x = 3.3, y = 4.4)
val p2 = p1.copy(y = 6.6)

方法具備多個參數列表

示例

代碼

abstract class Shape() {
    def draw(offset: Point = Point(0.0, 0.0))(f: String => Unit): Unit =
        f(s"draw(offset = $offset), ${this.toString}")
}

case class Circle(center: Point, radius: Double) extends Shape

調用有多個參數列表的draw方法

s.draw(Point(1.0, 2.0))(str => println(s"ShapesDrawingActor: $str"))
// 也能夠將圓括號替換爲花括號
s.draw(Point(1.0, 2.0)){str => println(s"ShapesDrawingActor: $str")}
// 或者這樣
s.draw(Point(1.0, 2.0)){str =>
    println(s"ShapesDrawingActor: $str")
}
// 亦或這樣
s.draw(Point(1.0, 2.0)){
    str => println(s"ShapesDrawingActor: $str")
}

優點

  • 代碼更清晰
  • 在以後的參數列表中進行類型判斷
  • 能夠用最後一個參數列表來推斷隱含參數.隱含參數是用implicit關鍵字聲明的參數.

Future簡介

  • scala.concurrent.Future是Scala提供的一個併發工具,其中的API使用隱含參數來減小冗餘代碼
  • 將任務封裝在Future中執行時,該任務的執行是異步的

示例

代碼

併發發出5個任務,並在任務結束時處理任務返回的結果.併發

// file: future.scala
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def sleep(millis: Long) = {
    Thread.sleep(millis)
}

def doWork(index: Int) = {
    sleep((math.random * 1000).toLong)
    index
}

(1 to 5) foreach { index =>
    val future = Future(doWork(index))

    future onSuccess {
        case answer: Int => println(s"Success! returned: $answer")
    }
    future onFailure {
        case th: Throwable => println(s"Failure! returned: $th")
    }
}

sleep(3000)     // 等待足夠長時間,確保工做進程結束
println("finito!")

運行

scala future.scalaapp

運行結果

Success! returned: 2
Success! returned: 4
Success! returned: 1
Success! returned: 5
Success! returned: 3
finito!

說明

  • 用foreach對一個從1到5的Range進行迭代,調用了scala.concurrent.Futrue.apply, 這是單例對象Future的工廠方法.
  • Future.apply返回一個新的Future對象,而後控制權就交給循環了,該對象將在另外一個線程中執行doWork(index)
  • 用onSuccess註冊一個回調函數,當future成功執行完畢後,該回調函數會被執行.這個回調函數是一個偏函數.
  • Future API容許咱們經過ExecutionContext來配置併發操做的執行.import scala.concurrent.ExecutionContext.Implicits.global語句導入了默認的ExecutionContext.示例中調用了3個方法,其中的這些方法的第二個參數列表具備隱含的ExecutionContext參數,因爲沒有指定,使用了默認的ExecutionContext.
  • 使用implicit關鍵字聲明變量爲implicit.只有被聲明爲implicit的函數參數才容許調用時不給出實參.

嵌套方法的定義和遞歸

方法的定義能夠嵌套.dom

代碼示例

代碼

// file: factorial.scala
def factorial(i: Int): Long = {
    def fact(i: Int, accumulator: Int): Long = {
        if (i <= 1)
            accumulator
        else
            fact(i - 1, i * accumulator)
    }

    fact(i, 1)
}

(0 to 5) foreach ( i => println(factorial(i)) )

運行

scala factorial.scala異步

輸出

1
1
2
6
24
120

字面量

整數字面量

  • 整數字面量能夠以十進制,八進制,十六進制的形式出現
類型 格式 例子
十進制 0或非零值,後面跟上0個活多個數字 0,1,321
十六進制 0x後面更上一個或多個十六進制數字(0-9,A-F,a-f) oxFF,0x1a3b
八進制 0後面跟上一個或多個八進制數字(0-7) 013,077

整數字面量

目標類型 下限 上限
Long -2^63 2^63-1
Int -2^31 2^31-1
Short -2^15 2^15-1
Char 0 2^16
Byte -2^7 2^7-1
  • 若是整數字面量的值超出了以上表格中所示的範圍,將會引起一個編譯錯誤.
  • 字面量類型默認推斷爲Int

浮點數字面量

  • 默認推斷類型爲Double

示例

.14
3.14
3.14F
3.14D
3E5
3.14e-5
3.14e+5
3.14e-4D

布爾型字面量

布爾型字面量能夠爲truefalseide

字符字面量

  • 字符字面量要麼是單引號內的一個可打印的Unicode字符,要麼是一個轉義序列.
  • 值在0~255的Unicode字符能夠用八進制數字的轉義形式表示,即一個反斜槓後面跟上最多三個八進制數字字符

字符常量示例

'A'
'\u0041'
'\n'
'012'
'\t'

字符轉義序列

轉義序列 含義
\b 退格(BS)
\t 水平製表符(HT)
\n 換行(LF)
\f 表格換行(FF)
\r 回車(CR)
" 雙引號(")
' 單引號(')
\ 反斜槓()

不可打印的Unicode字符是不容許的,如\u0009(水平製表符), 應該使用等價的轉義形式\t函數

字符串字面量

  • 字符串字面量是被雙引號和三重雙引號包圍的字符串序列

符號字面量

  • 符號是一些規定的字符串
  • 符號字面量是單引號後更上一個或多個數字,字母或下劃線,但第一個字符不能是數字
  • 符號字面量'id是表達式scala.Symbol("id")的簡寫形式
  • 若是須要建立包含空格的符號,能夠使用Symbol.apply, 如Symbol.apply(" Programming Scala ")

函數字面量

  • (i: Int, s: String) => s+i 是一個類型爲 Function2[Int, String, String] (返回值類型爲String)的函數字面量工具

  • 咱們能夠使用函數字面量來聲明變量,下面兩種聲明是等價的:

    val f1: (Int, String) => String     = (i, s) => s+i
    val f2: Function2[Int, String, String]  = (i, s) => s+i

元組字面量

  • Scala庫中包含TupleN類,如Tuple2, 用於組建N元素組

定義

val tup = ("strig", 2016)   // 定義了一個Tuple2的實例
val t1: (Int, String) = (1, "one")
val t2: Tuple2[Int, String] = (2, "two")

使用

// File: tuple.scala
val t = ("Hello", 1, 2.3)
println("print the whole tuple:" + t)
println("print the first item:" + t._1)
println("print the second item:" + t._2)
println("print the third item:" + t._3)

val (t1, t2, t3) = ("World", '!', 0x22)
println(t1 + ", " + t2 + ", " + t3)

val (t4, t5, t6) = Tuple3("World", '!', 0x22)
println(t4 + ", " + t5 + ", " + t6)

運行

scala tuple.scala

輸出

print the whole tuple:(Hello,1,2.3)
print the first item:Hello
print the second item:1
print the third item:2.3
World, !, 34
World, !, 34

兩元素的元組

兩元素的元組有時被簡稱爲pair.其定義方法有多種:

  • (1, "one")
  • 1 -> "one"
  • Tuple2(1, "one")

示例:

scala> val t = 1 -> "one"
t: (Int, String) = (1,one)

scala> t._1
res0: Int = 1

scala> t._2
res1: String = one

Option, Some,None: 避免使用null

  • Option有兩個具體的子類,SomeNone.
  • Some表示有值
  • None表示沒有值

封閉類的繼承

  • Scala設計了關鍵字sealed,其告訴編譯器全部的子類必須在同一個源文件中聲明.在Scala庫中,Some與None就是與Option聲明在同一源文件中,這一技術有效防止了Option類派生其餘子類型.
  • 若是要防止用戶派生任何子類, 能夠用final關鍵字聲明

用文件和名空間組織代碼

  • Scala沿用Java用包來表示命名空間的這一作法,但它更加靈活.
  • 文件名沒必要與類名一致
  • 包結構不必定要與目錄結構一致
  • 能夠定義與文件的"物理"位置獨立的包結構
  • Scala不容許在腳本中定義包,腳本被隱含包裝在一個對象中.在對象中聲明包是不容許的
  • 不能再類或對象中定義包

導入類型及其成員

  • _被當作通配符, 由於在Scala中,*容許用做函數名

示例

Scala中導入Java類型.

import java.awt._               // 導入包內全部類型
import java.io.File             // 導入包中單獨的Scala類型或Java類型
import java.io.File._           // 導入了java.io.File中全部的靜態方法和屬性.與之等價的Java import語句爲:
                              // import static java.io.File.*
import java.util.{Map, HashMap} // 選擇性導入
  • 導入是相對的
相關文章
相關標籤/搜索