簡(jiǎn)介
scala是一門綜合了面向?qū)ο蠛秃瘮?shù)式編程概念的靜態(tài)類型的編程語(yǔ)言见秽。
函數(shù)式編程以兩大核心理念為指導(dǎo):第一個(gè)理念是函數(shù)是一等的值嗜憔。(可以將函數(shù)作為參數(shù)傳遞給其他函數(shù)晤柄,作為返回值返回它們拦焚。)第二個(gè)核心理念是程序中的操作應(yīng)該將輸入值映射成輸出值,而不是當(dāng)場(chǎng)修改數(shù)據(jù)浑测。不可變數(shù)據(jù)結(jié)構(gòu)是函數(shù)式編程的基石之一翅阵。函數(shù)式編程的這個(gè)核心理念的另一種表述方法是不應(yīng)該有副作用。方法只能通過(guò)接受入?yún)⒑头祷亟Y(jié)果這兩種方式與外部環(huán)境通信迁央。
為什么要用Scala編程掷匠?
- 兼容性:Scala程序會(huì)被編譯成jvm字節(jié)碼♂Γ可以與Java無(wú)縫互調(diào)讹语。
- 精簡(jiǎn)性:Scala的類型推斷。
- 高級(jí)抽象蜂科。
- 靜態(tài)類型顽决。
快速入門
- 所有Java的基本類型在Scala包中都有對(duì)應(yīng)的類。
scala.Boolean對(duì)應(yīng)Java的boolean崇摄,scala.Float對(duì)應(yīng)Java的float擎值。
Scala的字符串是用Java的String類實(shí)現(xiàn)的慌烧。特質(zhì)(trait)跟Java的接口類似逐抑。
Scala的Unit類型跟Java的void類型類似。 - Scala變量分為兩種:val和var屹蚊。
val和Java的final變量類似厕氨,一旦初始化就不能被重新賦值。而var則不同汹粤,類似于Java的非final變量命斧,在整個(gè)生命周期內(nèi)var可以被重新賦值。
當(dāng)你用val定義一個(gè)變量時(shí)嘱兼,變量本身不能被重新賦值国葬,但是它指向的那個(gè)對(duì)象是有可能發(fā)生改變的。 - Scala的類型推斷能力,能夠推斷出那些不顯式指定的類型
Scala編譯器并不會(huì)推斷函數(shù)參數(shù)的類型 - 函數(shù)式編程與指令式編程
e.g.args.foreach(println)
- Scala用圓括號(hào)而不是方括號(hào)來(lái)訪問(wèn)數(shù)組
數(shù)組不過(guò)是類的實(shí)例汇四,這一點(diǎn)跟其他Scala實(shí)例沒(méi)有本質(zhì)區(qū)別接奈。 - 函數(shù)式編程的一個(gè)重要理念之一是方法不能有副作用。
一個(gè)方法唯一要做的是計(jì)算并返回一個(gè)值通孽。 - Scala數(shù)組是一個(gè)擁有相同類型的對(duì)象的可變序列序宦。
數(shù)組可變的對(duì)象。Scala的List是不可變的背苦。元組也是不可變的互捌。元組可以容納不同類型的元素。 - 為什么不在列表的末尾追加元素行剂?
因?yàn)橥┪沧芳釉氐牟僮魉枰獣r(shí)間隨著列表的大小線性增加秕噪。而使用:: 在列表的前面添加元素只需要常量的時(shí)間。 - 如果方法名的最后一個(gè)字符是冒號(hào)硼讽,該方法的調(diào)用會(huì)發(fā)生在它的右操作元上巢价。
- 訪問(wèn)元組中的元素為什么是_N形式?
背后的原因是列表的apply方法永遠(yuǎn)只返回同一種類型,但是元組中的元素可以是不同類型的。字段名是從1開(kāi)始而不是0開(kāi)始胧瓜,這是由其他同樣支持靜態(tài)類型的元組的語(yǔ)言設(shè)定的傳統(tǒng)壁榕。 - 集和映射
set和map提供了可變和不可變兩種選擇。
scala.collection
Set/Map
<<trait>>
|
scala.collection.immutable scala.collection.mutable
Set /Map Set/Map
<<trait>> <<trait>>
| |
scala.collection.immutable scala.collection.mutable
HashSet/HashMap HashSet/HashMap
- 識(shí)別函數(shù)式編程風(fēng)格
一個(gè)向函數(shù)式風(fēng)格轉(zhuǎn)變的方向是盡量不用var格郁。 - 從文件讀取文本行
import scala.io.Source
Source.fromFile(fileName).getLines()
# 返回一個(gè)Iterator[String]
類和對(duì)象
Scala可以對(duì)分號(hào)進(jìn)行自動(dòng)推斷。
字段保留了對(duì)象的狀態(tài),或者說(shuō)數(shù)據(jù)漏麦,而方法用這些數(shù)據(jù)來(lái)對(duì)對(duì)象執(zhí)行計(jì)算。
要將某個(gè)字段聲明為私有况褪,可以在字段前面加上private這個(gè)訪問(wèn)修飾符撕贞。
public是Scala的默認(rèn)訪問(wèn)級(jí)別。
Scala方法的參數(shù)的一個(gè)重要的特征是它們都是val而不是var测垛。
推薦的風(fēng)格是避免使用任何顯示的return語(yǔ)句捏膨。在沒(méi)有任何顯示的return語(yǔ)句時(shí),Scala方法返回的是該方法計(jì)算出的最后一個(gè)表達(dá)式的值食侮。
Scala類不允許由靜態(tài)成員号涯。Scala提供了單例對(duì)象。關(guān)鍵字是object锯七。
當(dāng)單例對(duì)象跟某個(gè)類共用同一個(gè)名字時(shí)链快,它被稱為這個(gè)類的伴生對(duì)象。同時(shí)眉尸,類又叫做這個(gè)單例對(duì)象的伴生類域蜗。類和它的伴生對(duì)象可以互相訪問(wèn)對(duì)方的私有成員巨双。不能實(shí)例化。直接調(diào)用伴生對(duì)象名霉祸。單例對(duì)象在有代碼首次訪問(wèn)時(shí)才被初始化炉峰。沒(méi)有同名的伴生類的單例對(duì)象稱為孤立對(duì)象。
類和單例對(duì)象的一個(gè)區(qū)別是單例對(duì)象不接受參數(shù)脉执,而類可以疼阔。
Scala在每個(gè)Scala源碼文件都隱式的引入了java.lang和scala包的成員,以及名為Predef的單例對(duì)象的所有成員半夷。
scala提供了一個(gè)特質(zhì)scala.App婆廊。
基礎(chǔ)類型和操作
Scala基礎(chǔ)類型:java.lang.String, scala.Int, Long, Short, Byte, Float, Double, Char, Boolean。
字符串插值:s插值器:對(duì)內(nèi)嵌的每個(gè)表達(dá)式求值巫橄,
raw插值器:不識(shí)別字符轉(zhuǎn)義序列淘邻,
f插值器:可以進(jìn)行格式化。
Scala提供了eq方法用于比較引用相等性的機(jī)制湘换。
富包裝類:scala.runtime.RichByte, scala.runtime.RichShort, ...
scala.collection.immutable.StringOps宾舅。
函數(shù)式對(duì)象
Scala編譯器會(huì)將你在類定義體中給出的非字段或方法定義的代碼編譯進(jìn)類的主構(gòu)造方法中。
關(guān)鍵字this指向當(dāng)前執(zhí)行方法的調(diào)用對(duì)象彩倚,當(dāng)被用在構(gòu)造方法里的時(shí)候筹我,指向被構(gòu)造的對(duì)象實(shí)例。
Scala的輔助構(gòu)造方法以def this(...)
開(kāi)始帆离。在Scala中蔬蕊,每個(gè)輔助構(gòu)造方法都必須首先調(diào)用同一個(gè)類的另一個(gè)構(gòu)造方法。主構(gòu)造方法就是類的單一入口哥谷。只有主構(gòu)造方法可以調(diào)用超類的構(gòu)造方法岸夯。
內(nèi)建的控制結(jié)構(gòu)
控制結(jié)構(gòu)包括:if, while, do while, for, try catch finally, match case。
if表達(dá)式可以有返回值们妥。val filename = if (!args.isEmpty) args(0) else "default.txt"
while循環(huán)沒(méi)有返回值猜扮。
for循環(huán)可以有返回值。val forLineLengths = for {file <- filesHere if file.getName.endsWith(".scala") line <- fileLines(file) trimmed = line.trim if trimmed.matches(".*for.*") } yield trimmed.length
match 表達(dá)式會(huì)返回值监婶。val friend = firstArg match { case "salt" => "pepper" case "chips" => "salsa" case "eggs" => "bacon" case _ => "huh?" } println(friend)
函數(shù)和閉包
匿名函數(shù):(x: Int) => x + 1
部分應(yīng)用的函數(shù)是一個(gè)表達(dá)式旅赢,在這個(gè)表達(dá)式中,并不給出函數(shù)需要的所有參數(shù)压储,而是給出部分鲜漩,或完全不給源譬。def sum(a: Int, b: Int, c: Int) = a + b + c; val a = sum _; a(1, 2, 3)
尾遞歸函數(shù)并不會(huì)在每次調(diào)用時(shí)構(gòu)建一個(gè)新的棧幀集惋,所有的調(diào)用都會(huì)在同一個(gè)棧幀中執(zhí)行。
組合和繼承
組合的意思是一個(gè)類可以包含對(duì)另一個(gè)類的引用踩娘,利用這個(gè)引用類來(lái)幫助它完成任務(wù)刮刑;而繼承是超類\子類的關(guān)系喉祭。
一個(gè)包含抽象成員的類本身也要聲明為抽象的,做法是在class關(guān)鍵字之前寫(xiě)上abstract修飾符雷绢。
一個(gè)方法只要沒(méi)有實(shí)現(xiàn)泛烙,那么它就是抽象的。
繼承的意思是超類的所有成員也是子類的成員翘紊,但是有兩個(gè)例外蔽氨。一個(gè)是超類的私有成員并不會(huì)被子類繼承;二是如果子類里已經(jīng)實(shí)現(xiàn)了相同名稱和參數(shù)的成員帆疟,那么該成員不會(huì)被繼承鹉究。
Scala要求在所有重寫(xiě)了父類具體成員的成員之前加上這個(gè)修飾符。
要調(diào)用超類的構(gòu)造方法踪宠,只需將你打算傳入的入?yún)⒎旁诔惷Q后的圓括號(hào)里即可自赔。
多態(tài)的意思是多種形式。動(dòng)態(tài)綁定的意思是說(shuō)實(shí)際被調(diào)用的方法實(shí)現(xiàn)是在運(yùn)行時(shí)基于對(duì)象的類決定的柳琢,而不是變量或者表達(dá)式的類型決定的绍妨。
工廠對(duì)象包含創(chuàng)建其他對(duì)象的方法。使用方用這些工廠方法來(lái)構(gòu)造對(duì)象柬脸,而不是直接用new構(gòu)建對(duì)象他去。
繼承關(guān)系
在Scala中,每個(gè)類都繼承自同一個(gè)名為Any的超類倒堕。Scala還在繼承關(guān)系的底部定義了Null和Nothing孤页,Nothing是每一個(gè)其他類的子類。
class Any() {
final def ==(that: Any): Boolean
final def !=(that: Any): Boolean
def equales(that: Any): Boolean
//
def ##: Int
def hashCode:Int
def toString: String
}
子類可以通過(guò)重寫(xiě)equals方法來(lái)定制==和!=的含義涩馆。
根類Any有兩個(gè)子類: AnyVal和AnyRef行施。AnyVal是Scala中所有值類的父類,Scala提供了幾個(gè)內(nèi)建的值類:Byte魂那、Short蛾号、Char、Int涯雅、Long鲜结、Float、Double活逆、Boolean和Unit精刷。前八個(gè)對(duì)應(yīng)Java的基本類型。另外的Unit對(duì)應(yīng)Java的void的類型蔗候。AnyRef是Scala所有引用類的基類怒允。在Java平臺(tái)上AnyRef事實(shí)上只是java.lang.Object的一個(gè)別名。AnyRef類定義了一個(gè)eq方法锈遥,該方法不能被重寫(xiě)纫事,實(shí)現(xiàn)為引用相等性勘畔,還定義了一個(gè)反義的方法ne。
Null類是null引用的類型丽惶,它是每個(gè)引用類的子類炫七。Nothing是每個(gè)其他類型的子類型。并不存在在個(gè)類型的任何值钾唬。Nothing的用途之一是給出非正常終止的信號(hào)万哪。
def error(message: String): Nothing = {
throw new RuntimeException(message)
}
def divide(x: Int, y: Int): Int = {
if (y != 0) x / y
else error("can't divide by zero")
}
特質(zhì)
特質(zhì)是Scala代碼復(fù)用的基礎(chǔ)單元。類可以同時(shí)混入任意數(shù)量的特質(zhì)抡秆∪榔裕可以使用extends或者with關(guān)鍵字將它混入類中。定義一個(gè)特質(zhì)使用trait關(guān)鍵字琅轧。特質(zhì)最常用的使用場(chǎng)景是將廋接口拓寬為富接口以及定義可疊加的修改伍绳。特質(zhì)與Java的接口類似,但是功能更強(qiáng)大乍桂。
類與特質(zhì)的區(qū)別是特質(zhì)不能有任何的類參數(shù)冲杀,特質(zhì)中的super的調(diào)用是動(dòng)態(tài)綁定的。
包和引入
Scala的引入可以出現(xiàn)在任何地方睹酌。
Scala對(duì)每個(gè)程序都隱式的添加了一些引入权谁。
import java.lang._
import scala._
import Predef._
標(biāo)private的成員只在包含該定義的類或?qū)ο蟮膬?nèi)部可見(jiàn),在Scala中憋沿,這個(gè)規(guī)則同樣適用于內(nèi)部類旺芽。
在Scala中,protected的成員只能從定義該成員的子類訪問(wèn)辐啄。
斷言和測(cè)試
斷言和測(cè)試是用來(lái)檢查軟件行為符合預(yù)期的兩種重要手段采章。
在Scala中,斷言的寫(xiě)法是對(duì)預(yù)定義方法assert的調(diào)用壶辜。如果條件condition不滿足悯舟,表達(dá)式assert(condition)將拋出AssertionError。assert還有另一個(gè)版本砸民,assert(condition, explanation)抵怎,condition不滿足,那么就拋出包含給定的explanation的AssertionError岭参。
ensuring() 這個(gè)方法可以被用于任何結(jié)果類型反惕。ensuring()是對(duì)返回結(jié)果行進(jìn)行斷言的方法。
用Scala寫(xiě)測(cè)試演侯,有很多選擇姿染,例如:ScalaTest、specs2和ScalaCheck蚌本。
樣例類和模式匹配
樣例類是Scala用來(lái)對(duì)對(duì)象進(jìn)行模式匹配而并不需要大量的樣板代碼的方式盔粹。帶有case這種修飾符的類稱作樣例類。模式匹配包含一系列以case關(guān)鍵字打頭的可選分支程癌。
密封類除了在同一個(gè)文件中定義的子類之外舷嗡,不能添加新的子類。只需要在類繼承關(guān)系的頂部那個(gè)類的類名前面加上sealed關(guān)鍵字就成為了密封類嵌莉。
Scala由一個(gè)名為Option的標(biāo)準(zhǔn)類型來(lái)表示可選值进萄。這樣的值可以有兩種形式:Some(x),其中x是那個(gè)實(shí)際的值锐峭;或者None對(duì)象中鼠,代表沒(méi)有值。將可選值解開(kāi)最常見(jiàn)的方式是通過(guò)模式匹配沿癞。
可變對(duì)象
對(duì)于可變對(duì)象而言援雇,方法調(diào)用或者字段訪問(wèn)的結(jié)果可能取決于之前這個(gè)對(duì)象被執(zhí)行了那些操作。同樣的操作在不同的時(shí)間會(huì)返回不同的結(jié)果椎扬。
在Scala中惫搏,每一個(gè)非私有的var成員都隱式的定義了對(duì)應(yīng)的getter和setter方法。
類型參數(shù)化
泛型的意思是我們用一個(gè)泛化的類或者特質(zhì)來(lái)定義許多具體的類型蚕涤。在Scala中筐赔,泛型類型默認(rèn)的子類型規(guī)則是不變的。在類型形參前面加上+
表示子類型關(guān)系在這個(gè)參數(shù)上是協(xié)變的揖铜。加上-
表示逆變的茴丰。類型參數(shù)是協(xié)變的、逆變的天吓、不變的被稱為類型參數(shù)的型變贿肩。+
和-
被稱為型變注解。用U >: T
這樣的語(yǔ)法定義了U
的下界為T
龄寞。用T <: U
這樣的語(yǔ)法定義了T
的上界為U
尸曼。
抽象成員
如果類或者特質(zhì)的某個(gè)成員在當(dāng)前類中沒(méi)有完整的定義,那么它就是抽象的萄焦。抽象成員的本意是為了讓聲明該成員的類的子類來(lái)實(shí)現(xiàn)控轿。在Scala中,抽象成員包括抽象方法拂封、抽象字段(val 茬射、var)、抽象類型(type)冒签。
trait Abstract {
type T
def transform(x: T): T
val initial: T
var current: T
}
#具體實(shí)現(xiàn)
class Concrete extends Abstract {
type T = String
def transform(x: String) = x + x
val initial = "hi"
var current = initial
}
創(chuàng)建新枚舉的方式是定義一個(gè)擴(kuò)展自scala.Enumeration類的對(duì)象在抛。
object Direction extends Enumeration {
val North = Value("North")
val East = Value("East")
val South = Value("South")
val West = Value("West")
}
#引入枚舉類的所有值
import Direction._
#遍歷枚舉的值
for (d <- Direction.values) print(d + " ")
#獲取值的編號(hào)
Direction.East.id #1
#獲取指定編號(hào)的值
Direction(1) #East
隱式轉(zhuǎn)換與隱式參數(shù)
隱式定義指的是那些我們?cè)试S編譯器插入程序以解決類型錯(cuò)誤的定義。關(guān)鍵字是implicit萧恕「账螅可以用implicit來(lái)標(biāo)記任何變量肠阱、函數(shù)、類和對(duì)象定義朴读。
implicit def intToString(x: Int) = x.toString
通常是把一些有用的隱式轉(zhuǎn)換放到一個(gè)命名為Preamble對(duì)象中屹徘,這樣就可以通過(guò)import Preamble._
來(lái)訪問(wèn)這些隱式轉(zhuǎn)換。
Scala總共有三個(gè)地方會(huì)使用到隱式定義:從一個(gè)類型轉(zhuǎn)換到一個(gè)預(yù)期的類型衅金;對(duì)某個(gè)成員選擇接收端(即字段噪伊、方法調(diào)用等)的轉(zhuǎn)換;隱式參數(shù)氮唯。
#隱式轉(zhuǎn)換到一個(gè)預(yù)期的參數(shù)
implicit def doubleToInt(x: Double) = x.toInt
val i: Int = 3.5
#只要你看見(jiàn)了有人調(diào)用了接受類中不存在的方法鉴吹,那么很可能使用了隱式轉(zhuǎn)換
#隱式類是一個(gè)以implicit關(guān)鍵字打頭的類
#隱式類必須存在于另一個(gè)對(duì)象、類或惩琉、特質(zhì)中
#隱式參數(shù)
class PreferredPrompt(val preference: String)
object Greeter {
def greet(name: String)(implicit prompt: PrefereedPrompt) = {
println("Welcome, " + name + ". The system is ready.")
println(prompt.preference)
}
}
object JoesPrefs {
implicit val prompt = new PreferredPrompt("Yes, Master> ")
}
import JoesPrefs._
#需要兩個(gè)參數(shù)豆励,但是只傳入了一個(gè)參數(shù),另一個(gè)參數(shù)是隱式傳入的瞒渠。
Greeter.greet("Joe")
#返回結(jié)果
Welcome, Joe. The system is ready.
Yes, master
當(dāng)前作用域內(nèi)由多個(gè)隱式轉(zhuǎn)換都滿足要求時(shí)肆糕,如果可用的轉(zhuǎn)換當(dāng)中有某個(gè)轉(zhuǎn)換嚴(yán)格來(lái)說(shuō)比其他的更具體,那么編譯器就會(huì)選擇這個(gè)更具體的轉(zhuǎn)換在孝。
實(shí)現(xiàn)列表
package scala
abstract class List[+T] {
def isEmpty: Boolean
def head: T
def tail: List[T]
}
case object Nil extends List[Nothing] {
override def isEmpty = true
def head: Nothing = throw new NoSuchElementException("head of empty list")
def tail: List[Nothing] = throw new NoSuchElementException("tail of empty list")
}
final case class ::[T](hd: U, private var tl: List[U]) extends List[U] {
def head = hd
def tail = tl
override def isEmpty: Boolean = false
}
package scala.collection.immutable
final class ListBuffer[T] extends Buffer[T] {
private var start: List[T] = Nil
private var last0: ::[T] = _
private var exported: Boolean = false
...
}
重訪for表達(dá)式
所有最終交出(yield)結(jié)果的for表達(dá)式都會(huì)被編譯器翻譯成對(duì)高階函數(shù)map诚啃、flatMap和withFilter的調(diào)用。所有不帶yield的for循環(huán)會(huì)被翻譯成更小集的高階函數(shù):只有withFilter和foreach私沮。
深入集合類
#集合繼承關(guān)系圖
Traversable
Iterable
Seq
IndexedSeq
Vector
ResizableArray
GenericArray
LinearSeq
MutableList
List
Stream
Buffer
ListBuffer
ArrayBuffer
Set
SortedSet
TreeSet
HashSet (可變的)
LinkedHashSet (有序的)
HashSet (不可變的)
BitSet
EmptySet, Set1, Set2, Set3, Set4
Map
SortedMap
TreeMap
HashMap (可變的)
LinkedHashMap (可變的)
HashMap (不可變的)
EmptyMap, Map1, Map2, Map3, Map4
- Traversable特質(zhì):
抽象方法:
def foreach[U](f: Elem => U)
具體方法:
++, map, flatMap, collect, toIndexedSeq, toIterable, toStream, toArray, toList, toSeq, toSet, toMap, isEmpty, nonEmpty, size, head, last, tail, init, slice, take, drop, filter, exists, sum, min, max mkString, addString, view, ... - Iterable特質(zhì):
該特質(zhì)的所有方法都是用抽象方法iterator來(lái)定義的始赎。
重寫(xiě)foreach方法:
def foreach[U](f: Elem => U): Unit = {
val it = iterator
while (it.hasNext) f(it.next())
}
位于Iterable之下有三個(gè)特質(zhì): Seq, Set, Map.
- Seq特質(zhì):
方法:
apply, length, indexOf, +:, :+, updated, sorted, sortWith, sortBy, reverse, startsWith, endsWith, contains, diff, union, ...
buffer:
方法:
+=, ++=, +=:, ++=:, insert, -=, remove, ... - Set特質(zhì):
是沒(méi)有重復(fù)元素的Iterable。
不可變集:
方法:
contains, apply, +, ++, -, --, union, diff, ...
可變集:
方法:
+=, ++=, add, -=, --=, remove, ... - Map特質(zhì):
是有鍵值對(duì)組成的Iterable仔燕。
不可變映射:
方法:
apply, get, getOrElse, contains, +, ++, updated, -, --, keys, keySet, values, ...
可變映射:
方法:
+=, ++=, put, -=, --=, remove, ... - List:
是有限的不可變序列 - Stream:
其元素是惰性計(jì)算的造垛。可以無(wú)限長(zhǎng)晰搀。
val str = 1 #:: 2 #:: 3 #:: Stream.empty
- Vector:
是對(duì)頭部之外的元素也提供高效訪問(wèn)的集合類型五辽。不可變。
val vec = scala.collection.immutable.Vector.empty
val vec2 = vec :+ 1 :+ 2
val vec3 = 100 +: vec2
- Stack:
不可變:
val stack = scala.collection.immutable.Stack.empty
val hasOne = stack.push(1)
hasOne.top
hasOne.pop
可變:
val stack = scala.collection.mutable.Stack[Int]
stack.push(1)
stack.top
stack.pop
- Queue:
不可變:
val empty = scala.collection.immutable.Queue[Int]()
val has1 = empty.enqueue(1)
val has123 = has1.enqueue(List(2, 3))
val (element, has123) = has123.dequeue
可變:
val queue = scala.collection.mutable.Queue[String]
queue += "a"
queue.dequeue
- Range:
1 to 3
5 to 14 by 3
1 until 3
- BitSet:
不可變:
val bits = scala.collection.immutable.BitSet.empty
可變:
val bits = scala.collection.mutable.BitSet.empty
bits += 1
- ListMap:
val map = scala.collection.immutable.ListMap(1 -> "one")
map(1)
- ArrayBuffer:
val buf = scala.collection.mutable.ArrayBuffer.empty
buf += 1
- ListBuffer:
val buf = scala.collection.mutable.ListBuffer.empty[Int]
buf += 1
- StringBuilder:
val buf = new StringBuilder
buf += 'a'
- Array:
和Java的數(shù)組一一對(duì)應(yīng)外恕。支持泛型杆逗。
Scala集合框架
提取器
提取器是擁有名為unapply的成員方法的對(duì)象。
正則表達(dá)式:import scala.util.matching.Regex
val regex = new Regex("""(-)?(\d+)(\.\d*)?""")
原生字符串是由一對(duì)三個(gè)連續(xù)雙引號(hào)括起來(lái)的字符序列鳞疲。
val regex = """(-)?(\d+)(\.\d*)?""".r
regex findFirstIn str
regex findAllIn str
regex findPrefixOf str
注解
Scala在內(nèi)部將注解表示為僅僅是對(duì)某個(gè)注解類的構(gòu)造方法的調(diào)用罪郊。
(將@換成new,就能得到一個(gè)合法的創(chuàng)建實(shí)例的表達(dá)式)
import annotation._
注解的用處:
- 自動(dòng)生成文檔尚洽,就像Scaladoc那樣悔橄。
- 格式化代碼。
- 檢查常見(jiàn)的代碼問(wèn)題。
- 類型檢查癣疟。
// 聲明該方法已經(jīng)過(guò)時(shí)了挣柬。
@deprecated("use newShinyMethod() instead")
def bigMistaks() = // ...
// 聲明不檢查
(e: @unchecked) match {
// 沒(méi)有全面覆蓋的case 。睛挚。邪蛔。
}
// 用在并發(fā)編程中。
@volatile
//二進(jìn)制序列化
@serializable
//不應(yīng)該被序列化的字段
@transient
//自動(dòng)為字段生成get和set方法
@scala.reflect.BeanProperty
使用XML
XML是一種半結(jié)構(gòu)化數(shù)據(jù)竞川。
import scala.xml.Elem
import scala.xml.NodeSeq
import scala.xml.Node
import scala.xml.XML
對(duì)象相等性
class Point (val x: Int, val y: Int) {
// 計(jì)算hash值
override def hashCode = (x, y).##
override def equals (other: Any) = other match {
case that: Point =>
(that canEqual this) &&
(this.x == that.x) && (this.y == that.y)
case _ => false
}
def canEqual(other: Any) = other.isInstanceOf[Point]
}
結(jié)合Scala和Java
Scala的實(shí)現(xiàn)方式是將代碼翻譯成標(biāo)準(zhǔn)的Java字節(jié)碼店溢。
Java并沒(méi)有單例對(duì)象的確切對(duì)應(yīng)叁熔,不過(guò)他的確有靜態(tài)方法委乌。Scala對(duì)單例對(duì)象的翻譯采用了靜態(tài)和實(shí)例方法相結(jié)合的方式。
編寫(xiě)任何特質(zhì)都會(huì)創(chuàng)建一個(gè)同名的Java接口荣回。
所有Scala方法都被翻譯成沒(méi)有聲明任何拋出異常的Java方法遭贸。