目錄
標識符
可用的字符
- 處理括號類字符,分隔符之外,其他所有的可打印的ASCII字符,如字母,數字,下划線和美元符號($)均可出現在Scala標識符中
- 插入符包括了(,) [,] {,and}
- 分隔符包括 ` ' " . ; ,等
- Scala還允許在標識符中使用編碼在 \u0020到\u007F之間的字符,如數學符號,想 / 和 < 這樣的操作符字符以及其他的一些符號
不能使用保留字.
普通標識符
- 常見的標識符往往由字母或下划線開頭,后面跟着一些字母,數字,下划線和$符
- Scala允許使用Unicode格式的字符
- $符在Scala內部會作為特定作用,盡量不要使用
- Scala編譯器會將下划線之后,空格之前的所有字符視為標識符的一部分
- 假如在下划線后輸入了操作符,那么不允許在操作符后輸入字母或數字
- 假如某一標識符以操作符開頭,那么后面的字符也必須是操作符字符
示例
val xyz_++= = 1
使用反引號定義標識符
可以通過反引號定義標識符,兩個反引號內的任意長度的字符串便是定義的標識符.
def `test that addition work`= assert(1 + 1 = 2)
無參數方法
- 對於不包含參數的方法,除了可以選擇使用中綴調用或后綴調用方式之外,Scala還允許用戶靈活決定是否使用括號
- 定義無參方法時省略了括號,那么在調用這些方法時必須省略括號
- 定義無參方法時添加了空括號,那么調用該方法時可以選擇省略或保留括號
幾個等價表達式
List(1, 2, 3, 4).filter((i: Int) => isEven(i)).foreach((i: Int) => println(i))
List(1, 2, 3, 4).filter(i => isEven(i)).foreach(i => println(i))
List(1, 2, 3, 4).filter(isEven).foreach(println)
List(1, 2, 3, 4) filter isEven foreach println
優先級規則
1. 所有字母
2. |
3. ^
4. &
5. < >
6. = !
7. :
8. + -
9. * / %
10. 其他特殊字符
- 所有操作符都是方法
- 並不是所有方法都是左結合
- 任何名字以冒號(:)結尾的方法均與其右邊的對象綁定
cons操作
- cons是constructor的縮寫
- cons操作指通過
::
方法將某一元素放置到列表前面
示例
scala> val list = List('c', 'd')
list: List[Char] = List(c, d)
scala> 'a' :: list
res1: List[Char] = List(a, c, d)
scala> val list = List('c', 'd')
list: List[Char] = List(c, d)
scala> 'b' :: list
res2: List[Char] = List(b, c, d)
scala> list.::('a')
res3: List[Char] = List(a, c, d)
scala> 'a' :: list
res4: List[Char] = List(a, c, d)
scala> 'b' :: list
res5: List[Char] = List(b, c, d)
注意:
-
'a' :: list
等價於list.::('a')
-
不能使用該方法重復插入多個字符
if語句
-
Scala的if語句可以向Java中一樣使用
if (2 + 2 = 5) { println("if") } else if (2 + 2 = 3) { println("else if") } else { println("else") }
-
Scala中的if語句是有返回值的. 可以將if表達式的結果值賦值給其他變量. 以下面代碼為例.
val configFile = new java.io.File("someFile.txt") val configFilePath = if (configFile.exists()) { configFile.getAbsolutePath() } else { configFile.createNewFile() configFile.getAbsolutePath() }
if語句返回值的類型也被稱為所有條件分支的最小上界類型,也就是與每條each子句可能返回值類型最接近的父類型.在上面例子中,
configFilePath
是if表達式的結果值,該if表達式將執行文件不存在的條件分支(假定),並返回新創建文件的絕對路徑.將if語句的返回值賦予變量configFilePath
.
Scala不支持三元表達式
循環
for推導式
for循環
示例
代碼
val list = List("A", "B", "C")
for (item <- list)
println(item)
輸出
A
B
C
生成器表達式
- 像
item <- list
這樣的表達式被稱為生成器表達式 - 該表達式會基於集合生成單獨的數值
- 左箭頭操作符(<-)用於對象列表這樣的集合進行遍歷
保護式: 篩選元素
- for語句中可以加入if表達式來篩選元素,這些表達式被稱為保護式(guard)
示例
代碼
val list = List("ABC", "CDE", "EFG")
for (item <- list
if item.contains("C")
)
println(item)
輸出
ABC
CDE
添加多個保護式
示例
val list = List("ABC", "BCD", "CDE")
for (item <- list
if item.contains("B")
if !item.startsWith("A")
)
println(item)
for (item <- list
if item.contains("B") && !item.startsWith("A")
)
println(item)
輸出
BCD
BCD
- 分別為兩個for循環的輸出
Yielding
- 使用
yielding
關鍵字能在for表達式中生成新的集合
示例
代碼
val list = List("ABC", "BCD", "CDE")
val filterItems = for {item <- list
if item.contains("B")
if !item.startsWith("A")
} yield item
filterItems
運行
scala> val list = List("ABC", "BCD", "CDE")
list: List[String] = List(ABC, BCD, CDE)
scala> val filterItems = for {item <- list
| if item.contains("B")
| if !item.startsWith("A")
| } yield item
filterItems: List[String] = List(BCD)
擴展作用域與值定義
- 能夠在for表達式中的最初部分定義值,並可在以后的表達式中使用該值
示例
代碼
val list = List("abc", "bcd", "cde")
val upcaseItems = for {
item <- list
upcaseItem = item.toUpperCase()
} yield upcaseItem
運行
scala> val list = List("abc", "bcd", "cde")
list: List[String] = List(abc, bcd, cde)
scala>
| val upcaseItems = for {
| item <- list
| upcaseItem = item.toUpperCase()
| } yield upcaseItem
upcaseItems: List[String] = List(ABC, BCD, CDE)
while循環
示例
while (表達式) {
do something
}
do...while循環
示例
var count = 0
do {
count += 1
} while(count < 10)
條件操作符
操作符 | 操作 |
---|---|
&& | 和操作 |
|| | 或操作 |
> | 大於 |
>= | 大於或等於 |
< | 小於 |
<= | 小於或等於 |
== | 等於 |
!= | 不等於 |
-
&&
和||
是短路操作符 -
在Java中
==
只會對對象引用進行比較, 調用equals
來比較字段值; Scala使用==
符執行邏輯上的相等檢查. 即調用equals
方法進行判斷.public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public boolean equals(Object obj) { return true; } public static void main(String args[]) { Person p1 = new Person("sun", 20); Person p2 = new Person("li", 20); System.out.println(p1 == p2); } } // 輸出: false
class Person(var name: String, var age: Int) { override def equals(obj: scala.Any): Boolean = true } val p1 = new Person("sun", 20) val p2 = new Person("sun", 20) println(p1 == p2) // 輸出: true
使用try...catch...final子句
- Scala使用模式匹配來捕獲異常, 而Java使用單獨的catch子句來捕獲各個異常
- 使用
case NonFatal(ex) => ...
子句使用scala.util.control.NonFatal
匹配了所有的非致命性異常 - 通過編寫
throw new MyBadException(...)
拋出異常 - 如果自定義異常是一個case類,那么拋出異常時可以省略new關鍵字
實例
try {
...
} catch {
case NonFatal(ex) => println(s"Non fatal exception! $ex")
case ...
} finally {
...
}
惰性賦值
- 惰性賦值是與傳名參數相關的技術
- 如果希望以延遲的方式初始化某值, 並且表達式不會被重復計算, 則需要使用惰性賦值
- 常見應用場景
- 由於表達式執行代價昂貴(比如打開一個數據庫連接), 希望能推遲該操作, 直到確實需要表達式結果時才執行它
- 為了縮短模塊啟動時間, 可以將當前不需要的某些工作推遲執行
- 為了確保對象中其他字段的初始化過程能優先執行, 需要將某些字段惰性化
示例
object ExpensiveResource {
lazy val resource: Int = init()
def init(): Int = {
// 某些代價昂貴的操作
0
}
}
- lazy關鍵字意味着求值過程會被推遲,只有需要時才會執行計算
- 首次使用惰性值時, 初始化代碼才會被執行一次, 這種只能執行一次的計算對於可變字段而言沒有任何意義.因此lazy關鍵字不能修飾var變量
- 通過**保護式來實現惰性值
枚舉
- Scala通過在標准庫中專門定義Enumeration類實現枚舉
示例一
代碼
// file: enum.scala
object Breed extends Enumeration {
type Breed = Value
val doberman = Value("Doberman Pinscher")
val yorkie = Value("Yorkshire Terrier")
val scottie = Value("Scottish Terrier")
val dane = Value("Great Dane")
val portie = Value("Portuguese Water Dog")
}
import Breed._
println("ID\tBreed")
for (breed <- Breed.values) println(s"${breed.id}\t$breed")
println("\nJust Terriers:")
Breed.values filter (_.toString.endsWith("Terrier")) foreach println
def isTerrier(b: Breed) = b.toString.endsWith("Terrier")
println("\nJust Terriers:")
Breed.values filter isTerrier foreach println
運行
scala enum.scala
輸出
ID Breed
0 Doberman Pinscher
1 Yorkshire Terrier
2 Scottish Terrier
3 Great Dane
4 Portuguese Water Dog
Just Terriers:
Yorkshire Terrier
Scottish Terrier
Just Terriers:
Yorkshire Terrier
Scottish Terrier
可插入字符串
下面是一個簡單示例:
val name = "Buck Trends"
println(s"Hello, $name")
格式化
下面是幾個對可插入字符串進行格式化的示例.
scala> val gross = 100000F
gross: Float = 100000.0
scala> val net = 64000F
net: Float = 64000.0
scala> val percent = (net / gross) * 100
percent: Float = 64.0
scala> println(f"$$${gross}%.2f vs. $$${net}%.2f or ${percent}%.1f%%")
$100000.00 vs. $64000.00 or 64.0%
scala> val s = "%02d: name = %s".format(5, "Dean Wampler")
s: String = 05: name = Dean Wampler
// 原生插入器
scala> val name = "Dean Wampler"
name: String = Dean Wampler
scala> s"123\n$name\n456"
res1: String =
123
Dean Wampler
456
scala> raw"123\n$name\n456"
res2: String = 123\nDean Wampler\n456
- 使用
$$
打印一個$
- 使用
%%
打印一個%