保留字
保留字 | 說明 |
---|---|
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不存在break
和continue
關鍵字
分號
- 分號是表達式之間的間隔
- 當一行結束時,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.scala
運行結果
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的函數參數才允許調用時不給出實參.
嵌套方法的定義和遞歸
方法的定義可以嵌套.
代碼示例
代碼
// 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
布爾型字面量
布爾型字面量可以為true
或false
字符字面量
- 字符字面量要么是單引號內的一個可打印的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
有兩個具體的子類,Some
和None
.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} // 選擇性導入
- 導入是相對的