Scala語言學習
基礎
- 安裝
Scala
-
REPL
(Read-Evaluate-Print-Loop shell
) - 處理數據
- 字面量:直接出現在源代碼中的數據
- 值
value
:val <identifier>[: <type>] = <data>
- 不可變的、有類型的存儲單元,支持類型推導
- 變量
variable
:var <identifier>[: <type>] = <data>
- 可變的、有類型的存儲單元,支持類型推導
- 可重新賦值,但是不可改變數據類型(支持類型轉換的例外)
- 命名:支持使用字母、數字和一些特殊的操作符字符
例如可以使用
等,不能使用
[]
和.
-
合法命名規則
- 不以數字開頭
- 以數字開頭的話,編譯器最初會把解析到的第一個數字當成一個字面量數字,然后后面解析到其他非數字字符就會出錯
- 一個或多個除反引用號外的任意字符,這些字符必須包圍在一對反引號之中
val `a.b` = 4
- 不以數字開頭
- 類型
-
核心數值類型
-
Byte
、Short
、Int
、Long
、Float
、Double
-
toType方法
手動完成類型間轉換 - 與
JVM
包裝數值類型可以互操作
-
-
字符串
String
建立在
Java
的String
基礎上與
Java
不同,==
會檢查字符串真正的想等性,而不是對象引用想等性三重引號創建多行
String
,類似Python
""" your string """
-
字符串內插
- 在字符串的第一個雙引號前面增加一個
s
前綴,使用美元符$
指示插入數據的引用(某些容易區分的情況下,大括號{}
可以省略,但是加上更容易區分)
val approx = 355/113f println(s"Pi, using 355/133, is about ${approx}.")
- 在字符串的第一個雙引號前面增加一個
-
字符串內插的替代格式可以使用
printf
語法(java.util.Formatter
)- 在字符串前面添加
f
前綴
scala> val item = "apple" scala> f"Enjoying this $item ${355/133.0}%.5f times today.")
- 在字符串前面添加
-
正則表達式(基于
Java
類java.util.regex.Pattern
)- 用正則表達式捕獲值
val <Regex value>(<identifier>) = <input string>)
val pattern = """.* apple ([\d.]+) times .*""".r
val pattern(amountText) = input
val amount = amountText.toDouble
- 用正則表達式捕獲值
-
Scala
類型概述
Scala類型概述-
Nothing
:所有類型的子類 -
Null
:所有指示null
值的AnyRef
類型的子類 -
Unit
:指示沒有值(類似void
) -
Any
:Scala
中所有類型的根 -
AnyVal
:所有值類型的根 -
AnyRef
:所有引用(非值)類型的根
-
Scala
不支持其他類型到Boolean類型
的自動轉換。非null字符串不會計算為true
-
元組
(<value 1>,<value 2>[,<value 3>...])
- 不同于列表和數組,沒有辦法迭代處理一個元組中的元素,元組的作用只是作為多個值的容器
- 根據元素的索引訪問元組中的元素(下劃線加上索引,索引從1開始)
- 創建一個大小為2的元組,也可以使用關系操作符(
->
),表示元組中的鍵值對
-
表達式和條件式
-
表達式塊(用
{}
結合多個表達式創建,最后一個表達式作為表達式塊的返回值)- 可嵌套、跨行,多個表達式寫在一行需要
;
分隔
- 可嵌套、跨行,多個表達式寫在一行需要
語句:不返回值的表達式
-
if...else
表達式塊if (<Boolean expression>) <expression>
if (<Boolean expression>) <expression> else <expression>
-
匹配表達式(類似
switch
)-
Scala
匹配表達式支持匹配如值、類型、正則表達式、數值范圍和數據結構內容
<expression> match{ case <pattern match> => <expression> [case ...] }
- 可以使用模式替換式(
pattern alternative
),匹配多種內容 case <pattern 1> | <pattern 2> .. => <one or more expressions>
- 增加通配模式,放止輸入內容無法匹配的情況運行時異常
- 值綁定模式
case <identifier> => <one or more expressions>
- 將輸入綁定到一個特定的字面量上,如果不匹配就會進入這個綁定值的情況
- 使用通配符
_
:相當于匿名占位符,將在運行時替換為一個表達式的值- 與值綁定的不同在于不能再
case
表達式塊中訪問通配符的值
- 與值綁定的不同在于不能再
- 值綁定模式
- 用模式哨位匹配
- 增加一個
if
語句,為匹配表達式增加條件邏輯 case <pattern> if <Boolean expression> => <one or more expression>
- 增加一個
- 用模式變量匹配類型
- 匹配輸入表達式的類型
case <identifier>: <type> => <one or more expressions>
-
-
循環
-
Range
(范圍)數據結構<starting integer> [to|until] <ending integer> [by increment]
-
基本for循環迭代處理
for (<indentifier> <- <iterator>) [yield] [<expression>]
-
yield
:如果指定,則調用的所有表達式的返回值將作為一個集合返回,如果沒有指定,則調用表達式,但是不能訪問它的返回值 for (x <- 1 to 7){println(s"Day $x:")}
-
迭代器哨位(過濾器)
for (<indentifier> <- <iterator> if <Boolean expression>)...
threes = for(i <- 1 to 20 if i%3 == 0) yield i
-
嵌套迭代器
for{ x <- 1 to 2 y <- 1 to 3 } { print(s"($x,$y) ")}
-
值綁定
for (<indentifier> <- <iterator>; <identifier> = <expression>)...
for(i <- 0 to 8; pow = 1 <<i) yield pow
-
While
和Do/While
循環while(<Boolean expression>) statement
-
函數
- 定義無輸入的函數
def <identifier> = <expression>
def <identifier>() = <expression>
- 如果定義函數時沒加小括號,則調用時也不可以加小括號,而加了小括號的無輸入函數調用時可以不加小括號
- 定義函數時指定返回類型
def <identifier>: <type> = <expression>
- 定義函數
def <identifier>(<identifier>: <type>[,...]): <type> = <expression>
- 過程:沒有返回值的函數
- 使用表達式塊調用函數
- 當使用一個參數調用函數時,可以使用表達式塊返回的結果發送參數
- 遞歸函數
- 遞歸函數可能會遇到“棧溢出”錯誤,
Scala
編譯器可以使用尾遞歸優化一些遞歸函數 - 利用尾遞歸優化的函數,遞歸調用不會創建新的空間,而是使用當前函數的棧空間
- 只有最后一個語句是遞歸調用的函數才能由
Scala
編譯器完成尾遞歸優化 - 可以利用函數注解來標志一個函數將完成尾遞歸優化
@annotation.tailrec
- 遞歸函數可能會遇到“棧溢出”錯誤,
- 嵌套函數
- 用命名參數調用函數
- 可以不按原先定義的順序指定參數
- 有默認值的參數
-
Vararg
參數- 這是一個函數參數,可以匹配調用者的0個或多個實參
-
vararg
參數后面不能跟非vararg
參數,因為無法加以區分 -
vararg
參數實現為一個集合,可以通過迭代器訪問 - 要標志一個參數匹配一個或者多個輸入實參,在函數定義中需要該參數類型后面增加一個
*
號 - 例如
def sum(items: Int*): Int = {...}
- 參數組
- 可以把參數表分解為參數組,每個參數組用小括號分割
- 例如
def max(x:Int)(y:Int) = if (x > y) x else y
- 類型參數
- 類型參數指示了值參數類型或返回值類型
- 函數參數或返回值的類型不再固定,而是可以由函數調用者設置
def <function-name>[type-name](<parameter-name>:<type-name>): <type-name>...
- 例如
def identity[A](a: A): A = a
- 方法和操作符
- 中綴點記法:
<class instance>.<method>[(<parameters>)]
-
Scala
中使用的所有算術運算符都是方法 -
Scala
的操作符記法允許使用空格分隔對象、操作符方法和方法的參數(只有一個) - 例如
2 + 3
和2.+(3)
是一樣的 - 操作符記法:
<object> <method> <parameter>
- 如果要調用多個參數,則必須將多個參數包含在
()
中
- 如果要調用多個參數,則必須將多個參數包含在
- 中綴點記法:
首類函數
- “首類”表示函數不僅能得到聲明和調用,還可以作為一個數據結構用在這個語言的任何地方
- 高階函數:接受其他函數作為參數,或者使用函數作為返回值
- 聲明式編程:要求使用高階函數或其他機制聲明要做的工作,而不手動實現
- 命令式編程:總要明確指定操作的邏輯流
- 函數類型和值
函數的類型是其輸入類型與返回值類型的一個簡單組合,用一個箭頭從輸入類型指向輸出類型
-
([<type>, ...]) => <type>
def double(x: Int): Int = x*2 val myDouble: (Int) => Int = double val myDoubleCopy = myDouble val myDouble2 = double _
-
myDouble
就是一個值,只不過這個值可以調用 - 一個函數值可以賦值給一個新值
-
myDouble
必須有顯示的類型,以區分它是一個函數值,而不是一個函數調用(如果函數只有單個參數可以省略小括號) -
val <identifier> = <function name> _
:使用通配符為函數賦值
-
- 函數字面量
- 創建一個沒有名字的函數并把這個函數賦值一個新的函數值
val doubler = (x: Int) => x * 2
- 函數字面量是所賦數據的一個字面量表達式
- 其他名字:
匿名函數
、Lambda表達式
、Lambdas
、function0,function1,function2,...
(Scala
編譯器對字面量的叫法。根據輸入參數的個數而定,單參數就叫<function1>
) - 語法:
([<identifier>: <type>, ...]) => <expression>
- 占位符語法
函數字面量的一種縮寫形式,將命名參數替換為通配符(
_
)-
使用條件
- 函數的現實類型在字面量之外指定(明確好輸入輸出)
- 輸入參數最多只使用一次(因為只能按照位置匹配一次,多個占位符有著相同的符號,匹配之后就無法確定需要的參數)
-
示例
def combination(x: Int, y: Int, f: (Int,Int) => Int) = f(x,y) combination(23, 12, _*_)
def tripleOp[A,B](a: A, b: A, c: A, f: (A, A, A) => B) => f(a, b, c) tripleOp[Int, Int](23, 92, 14, _ * _ + _) tripleOp[Int, Double](23, 92, 14, 1.0 * _ / _ / _)
- 部分應用函數和柯里化
功能:為函數保留一些重復使用的參數
-
方法一:部分應用(
partially apply
)函數,使用通配符替代其他參數(函數按位置匹配)def factorOf(x: Int, y: Int) = y % x == 0 val mutipleOf3 = factorOf(3, _: Int) val y = mutipleOf3(78)
-
方法二:函數柯里化(
curring
,討好的意思),使用參數組-
有多個參數表的函數可以認為是多個函數的一個鏈。單個參數表則認為是一個單獨的函數調用
def factorOf(x: Int)(y: Int) = y % x == 0 val isEven = factorOf(2) _ val z = isEven(32) // z = true
def factorOf(x: Int)(y: Int)
的函數類型為Int => Int => Boolean
-
- 傳名參數
一種函數參數類型:可以取一個值,也可以取最終返回一個值的函數
-
語法:
<identifier>: => <type>
scala> def doubles(x: => Int) = { | println("Now doubling" + x) | x * 2 | } doubles: (x: => Int)Int scala> doubles(5) Now doubling 5 res1: Int = 10 scala> def f(i: Int) = { println(s"Hello from f($i)"); i } f: (i: Int)Int scala> doubles( f(8) ) Hello from f(8) Now doubling 8 Hello from f(8) //doubles調用兩次x,所以f函數也調用兩次 res2: Int = 16
- 偏函數
- 有些函數并不能支持滿足輸入類型的所有可能值。這種函數稱為偏函數,因為它們只能部分應用于輸入數據
- 用函數字面量塊調用高階函數
- 實際上就是輸入的參數類型是函數,那個輸入參數可以用表達式塊或者函數字面量來代替
- 好處
- 將單獨的代碼塊包為在工具函數中
- 管理數據庫事務,即高階函數打開會話,調用函數參數,然后commit或者rollback結束事務
- 重新嘗試處理可能的錯誤,將函數參數調用指定的次數,直到不再產生錯誤
- 根據局部、全局或者外部值有條件地調用函數參數
常用集合
- 列表、集和映射
-
List
:不可變的單鏈表- 訪問列表中的單個元素,可以作為一個函數調用這個列表,并提供一個索引號(從0開始)
- List是一個不可變的遞歸數據結構(鏈表),列表中的每一項都有自己的表頭和越來越短的表尾
- 所有列表都有一個
Nil
實例作為終結點,可以通過比較當前元素與Nil
來檢查是否到達列表表尾(Nil
實際上是List[Nothing]
的一個單例實例)
-
Set
:不可變的無序集合 -
Map
:不可變的鍵值庫,也稱為散列映射、字典或關聯數組 -
List
、Set
、Map
的根類型都是Iterable
-
foreach()
:取一個函數,對列表中的每一項,分別調用這個函數 -
map()
:取一個函數,將一個列表元素轉換為另一個值或類型 -
reduce()
:取一個函數,將兩個列表元素結合為一個元素
-
-
-
Cons
操作符可以通過
cons
(construct
的簡寫)操作符來構建列表-
使用
Nil
為基礎,并使用右結合的cons操作符::
綁定元素,就可以構建列表val numbersOld = List(1,2,3) val numbers = 1 :: 2 :: 3 :: Nil
-
::
是List
的一個方法,它取一個值,這會成為新列表的表頭val first = Nil.::(1) // 1 -> Nil
- 列表算術運算
- 因為
List
是一個不可變的集合,所有“修改”是指“返回一個新列表,其中包含所請求的修改” - 謂詞函數(
predicate function
):得到一個輸入值后會相應地返回true
或false
-
::
:為列表追加單個元素 -
:::
:為列表追加另一個列表 -
++
:為列表追加另一個集合 -
==
:判斷集合類型和元素內容是否相同 -
distinct
:返回不包含重復的列表 -
drop
:去除列表前n個元素 -
filter
:輸入一個謂詞函數,過濾掉指定的元素 -
flatten
:將一個包含列表的列表轉換為元素列表 -
partition
:輸入一個謂詞函數,將元素分組,由兩個列表組成一個元組 -
reverse
:逆轉列表 -
slice
:切片,輸入切片的開頭和結尾,輸出不包括結尾 -
sortBy
:根據指定函數排序 -
sorted
:根據自然順序排序 -
splitAt
:根據指定索引將列表切分成兩個 -
take
:從列表抽取前n個元素 -
zip
:兩個列表合并為一個元組列表
- 因為
- 映射列表
-
collect
:使用偏函數轉換各個元素,保留可應用的元素 -
flatMap
:給定一個函數轉換各個元素,扁平化結果(消除列表中的列表,這種嵌套結構) -
map
:使用給定函數轉換各個元素 -
Scala
可以把Java數組
轉換為它自己的類型Array
-
- 歸約列表
- 將列表收縮為單個值
-
Scala
的集合支持:- 數學歸約:
max
、min
、product
、sum
- 邏輯歸約:
contains
、endsWith
、exists
、forall
、startsWith
- 通用的高階操作,折疊,可以用來創建任何其他類型的列表歸約算法
-
fold
、foldLeft
、foldRight
、reduce
、reduceLeft
、reduceRight
、scan
、scanLeft
、scanRight
-
- 數學歸約:
- 轉換集合
-
mkString
:根據指定分隔符將一個集合轉換為String
-
toBuffer
:將一個不可變的集合轉變為可變的集合 -
toList
:將一個集合轉變為List
-
toMap
:將一個2元元組的集合轉換為一個Map
-
toSet
:將一個集合轉換為一個Set
-
toString
:將一個集合呈現為一個String
,包括集合的類型
-
-
Java
和Scala
集合兼容性- 默認情況下兩者集合類型是不兼容的
- 添加
JavaConverters
:import collection.JavaConverters._
- 集合轉換:
asJava
、asScala
- 使用集合的模式匹配
- 匹配表達式、模式哨衛、值綁定
- 模式匹配是
Scala語言
的一個核心特性
更多集合
-
可變的集合類型 : 不可變的集合類型
-
collection.mutable.Buffer
:collection.imutable.List
-
collection.mutable.Set
:collection.imutable.Set
-
collection.mutable.Map
:collection.imutable.Map
- 使用
toList
、toSet
、toMap
將可變集合類型轉換回不可變的集合類型
-
-
從不可變集合創建可變集合
- 不可變集合
List
、Map
和Set
都可以使用toBuffer方法
轉換為可變的collection.mutable.Buffer
類型
- 不可變集合
-
使用集合構建器
-
Builder
:生成指定的集合類型,只支持追加操作 Set.newBuilder[Char]
- 需要調用
result方法
得到最終結果
-
-
數組
- Array是一個大小固定的可變索引集合,實際只是Java數組類型的一個包裝器,另外還提供了隱含類高級特性,使它可以項序列一樣使用
val numbers = Array(1, 2, 3, 4)
-
Seq
和序列-
Seq
是所有序列的根類型
序列集合層次體系 Seq
:所有序列的根類型,List()
的快捷方式IndexedSeq
:索引序列的根類型,Vector()
的快捷方式Vector
:這一類列表有一個后備Array
實例,可以按索引訪問Range
:整數范圍。動態生成數據LinearSeq
:線性(鏈表)序列的根類型List
:元素的單鏈表Queue
:先進先出列表Stack
:后進先出列表Stream
:懶列表。訪問元素時才增加相應元素String
:字符集合,擴展了Iterable
-
-
Stream
懶集合,由一個或多個啟示元素和一個遞歸函數生成。流可能是無界的,理論上是無限的集合,只是在訪問元素時才回生成這個元素
使用
Stream.cons
用表頭表尾構建一個新的流,替代語法,可以使用#::
操作符示例:
def inc(head: Int): Stream[Int] = head #:: inc(head+1)
-
創建一個有界的流
def to(head: Char, end: Char): Stream[Char] = (head > end) match { case true => Stream.empty case false => head #:: to((head+1).toChar, end) }
-
一元集合
- 支持類似
Iterable
中的變換操作,但是包含的元素不能多于1個
- 支持類似
-
Option
集合- 擴展了
Iterable
的一個一元集合,Option類型
表示一個值的存在或不存在 -
Option
可以安全地替代null
值,告訴用戶這個值可能不存在,從而減少出發NullPointerException異常
的可能性 - 另一些開發人員把它看作是構建操作鏈的一種更為安全的方法,確保操作鏈中只包含有效的值
-
Option
依賴兩個子類型提供的具體實現:Some
和None
-
Some
:一個類型參數化的單元素集合 -
None
:一個空集合。None
類型沒有類型參數,因為它永遠不包含任何內容 - 用
isDefined
和isEmpty
分別檢查一個給定的Option
是Some
還是None
-
-
Option
集合提供了一種安全的機制,而且還提供了一些操作來存儲和變換可能存在也可能不存在的值,還提供了一些安全操作可以抽取可能存在的值 - 警告:避免使用
Option.get()
,此方法不安全,對None
調用get()
將導致運行時錯誤 - 安全的
Option
抽取操作fold
-
getOrElse
:為Some
,則返回值;為None
,則返回傳名參數的結果 -
orElse
:非空,返回這個Option
,否則從給定的傳名參數返回一個Option
- 匹配表達式
match{ case Some(x) => x; case None => -1 }
- 擴展了
-
Try
集合- 將錯誤處理轉變為集合管理。提供一種機制來捕獲給定函數參數中發生的錯誤,并返回這個錯誤。
-
Scala
拋出一個異常會中斷程序流,并把控制交回給最近的處理器來處理這個特定的異常。未處理的異常會終止應用。 -
Scala
支持try{}..catch{}
塊。 - 推薦使用
util.Try()
,因為它提供了一種更安全、更有表述性,而且純粹一元的方法來處理錯誤 -
util.Try
類型沒有具體實現,但是有兩個已實現的子類型Success
和Failure
- 使用Try的錯誤處理方法
flatMap
:對于Success
,調用一個同樣返回util.Try
的函數,從而將當前返回值映射到一個新的內嵌返回值foreach
:一旦Success
,執行給定的函數,Failure
則什么都不做getOrElse
:返回Success
中的內嵌值,對于Failure
則返回傳名參數的值orElse
:與flatMap
相反。對于Failure
,調用一個同樣返回util.Try
的函數toOption
:將util.Try
轉換為Option
,缺點是丟失內嵌的Exception
map
:對于Success
,調用一個函數,將內嵌值映射到一個新值匹配表達式
match { case util.Success(x) =>x; case util.Failure(error) => -1 }
-
什么都不做:只需要允許異常在調用棧中向上傳播,直到被捕獲或者導致當前應用退出
val input = " 123 " val result = util.Try(input.toInt) orElse util.Try(input.trim.toInt) result foreach { r => println(s"Parsed '$input' to $r!") } val x = result match { case util.Success(x) => Some(x) case util.Failure(ex) => { println(s"Couldn't parse input '$input'") None } }
-
Future
集合-
concurrent.Future
,發起一個后臺任務 -
future
表示一個可能的值,并提供了安全操作來串鏈其他操作或者抽取值。與Option
和Try
不同,future的值不是立即可用,因為創建future
時后臺任務可能仍在工作。 - 支持在并發線程中運行后臺任務。
- 調用
future
并提供一個函數會在一個單獨的線程中執行該函數,而當前線程仍繼續操作 - 在創建
future
之前,必須指定當前會話或應用的“上下文”來并發運行函數,默認使用global上下文
import concurrent.ExecutionContext.Implicits.global
- 可以設置回調函數或另外的
future
,當future
任務執行完成時,執行這個回調或者future
- 異步處理
future
-
fallbackTo
:將第二個future
串鏈到第一個future
,如果第一個future
不成功,則調用第二個future
-
flatMap
:如果第一個成功,則使用第一個的返回值調用第二個future
-
map
:將給定的函數串鏈到future
,如果future
成功,則其返回值將用來調用這個函數 -
onComplete
:future
任務完成后,將用一個util.Try
調用指定函數,其中包含一個值(成功)或者一個異常(失敗) -
onFailure
:如果future
任務拋出一個異常,將使用這個異常來調用指定函數 -
onSuccess
:如果future
任務成功完成,將使用返回值來調用給定函數 -
Future.sequence
:并發地運行給定序列中的future
,返回一個新的future
-
- 同步處理
future
-
concurrent.Await.result()
,取后臺線程和一個最大等待時間 - 等待時間:
import concurrent.duration._
- 等待10s:
val maxTime = Duration(10, SECONDS)
-
-
類
-
基礎
- 在
Scala
中,類參數在類名后指定,就像函數定義中函數參數跟在函數名后面一樣。類參數可以用來初始化字段(類中的值和變量),或者用于傳入函數,但是一旦類已經創建,這些參數就不再可用 - 可以把某個字段聲明為類參數,通過在類參數前增加
val
或者var
,類參數就成為類中的一個字段 -
Scala
中,一個類可以使用extends
關鍵字擴展最多一個其他類,另外可以用override
關鍵字覆蓋所繼承方法的行為 - 類中的字段和方法用
this
關鍵字訪問,父類中的字段和方法可以用super
關鍵字訪問 -
Scala
多態指類能夠采用其他兼容類的形式。“兼容”指一個子類的實例可以用于替代其父類的實例,但是反過來不行
- 在
-
定義類
class <identifier> [type-parameters] [([val|var] <identifier>: <type>[, ...])] //輸入參數可以有默認值 [extends <identifier>[type-parameters](<input parameters>)] //繼承父類可以有輸入參數 [{ fields, methods, and classes }]
- 實例就是一個內存分配,提供了類字段的存儲空間。這個動作(即預留空間來分配一個類的內容)稱為實例化
- 訪問類的字段和方法:標準中綴點記法、中綴操作符記法
-
抽象類
- 將由其他類擴展的一個類,而自己不能實例化
- 由
abstract
關鍵字指定 - 定義其子類必須有的核心字段和方法,但一般不提供具體實現(可以有默認實現)
- 基于多態,如果一個值的類型為抽象類,它可以具體指向某個非抽象子類的實例,調用方法時實際上最后會在子類上調用
重載方法
-
apply
方法- 名為“
apply
”的方法有時是指它要作為一個默認方法或一個注入方法,可以直接調用而不需要方法名 - 實際是一種快捷方式,可以使用小括號觸發功能而不需要方法名,就如
python
的__call__
方法,以及pytorch
的forward
- 名為“
-
懶值
- 定義一個值時可以在
val
關鍵字前面加上關鍵字lazy
來創建一個懶值 - 類中使用的字段(值和變量)都是在類第一次實例化時創建的,而懶值是第一次調用時創建
- 要確保時間或者性能敏感操作在類的生命周期中只執行一次,懶值則是一種很好的方法
- 常用于存儲基于文件的屬性、打開的數據庫鏈接,以及其他只有在確實必要時才初始化的不可變數據等信息。
- 定義一個值時可以在
-
包裝
- 為
Scala
文件定義包:package <identifier>
- 源文件要存儲在與包匹配的目錄中
- 訪問包裝類:用點分隔的包路徑或者導入包
- 與
Java
不同,代碼中的任何位置都可以使用import
,與python
類似 - 支持使用
_
操作符導入一個包的全部內容 - 導入組:
import <package>.{<class 1>[,<class 2>...]}
- 使用導入別名:
import <package>.{<original name> => <alias>}
- 包裝語法:包作為一個塊,用大括號包圍它的類
package <identifier> { <class definitions> }
- 為
-
私密性控制
- 默認地,
Scala
不會增加私密性控制 -
protected
:同一個類或者子類中的代碼才能訪問 -
private
:僅定義這個字段或方法的類可以訪問
- 默認地,
-
私密性訪問修飾符
- 包級保護
- 另外,可以根據另一個類的親密性覆蓋這些策略
- 實例級保護
- 包級保護
-
最終類和密封類
-
final
類不能在子類中被覆蓋,final
關鍵字定義的值,變量或方法,可以確保所有子類都將使用這個實現 -
sealed
密封類- 密封類會限制一個類的子類必須位于福勒所在的同一個文件中
-
對象、Case類和Trait
- 對象
object
- 一種類類型,只能有不超過1個實例,也就是單例(
singleton
) -
Java
和其他語言的某些字段和方法為“靜態”或“全局”,對象可以提供類似的功能,不過將它們與可實例化的類解耦合 - 對象不是用
new
關鍵字創建,只需要按名字直接訪問,在首次訪問時自動實例化(第一次訪問前,不會實例化) - 定義對象用
object
關鍵字,沒有任何輸入參數,對象不能擴展,但是別的類可以繼承它 - 定義:
object <identifier> [extends <identifier>] [{ fields, methods, and classes }]
- 最適合
object
的函數是純函數和處理外部I/O
的函數- 純函數:會返回完全由其輸入計算得到的結果,而沒有任何副作用
-
I/O
函數:處理外部數據的函數,如處理文件、數據庫和外部服務
-
apply
方法和伴生對象工廠模式是一種很流行的方法,可以從伴生對象生成一個類的新實例。
-
伴生對象是與類同名的一個對象,與類在同一個文件中定義
class Multiplier(val x: Int) { def product(y: Int) = x * y } object Multiplier { def apply(x: Int) = new Multiplier(x) }
- 使用對象的命令行應用
- 使用對象中的一個
main
方法作為應用的入口點 def main(args: Array[String]) { ... }
- 使用對象中的一個
-
Case
類case class <identifier> ([var] <identifier>: <type>[,...]) [extends <identifier>(<input-parameters>)] [{ fields and methods }]
- 不可實例化的類,包含多個自動生成的方法,包括一個自動生成的伴生對象
- 適合數據傳輸對象,主要用于存儲數據
-
val
關鍵字可以用,但是case
類默認將輸入參數轉換為值字段,所以沒必要添加,如果需要一個變量字段,則使用var
關鍵字 -
case
類方法-
apply
:對象object
中,一個工廠方法,用于實例化case
類 -
copy
:類中,返回實例的一個副本 -
equals
:類中 -
hashCode
:類中 -
toString
:類中 -
unapply
:對象中,將實例抽取到一個字段元組,從而可以使用case
類實例完成模式匹配
-
-
Trait
-
trait
不能實例化,支持多重繼承的類 -
trait
不能有類參數,但可以有類型參數 - 定義:
trait <identifier> [extends <identifier>] [{ fields, methods, and classes }]
- 用with關鍵字為類增加一個或多個
trait
,類沒有擴展trait
,而是被trait
擴展,trait
為現有的類增加新的功能或者配置,這個特性也稱為依賴注入-
Spring
通過定制Java注解
和初始化模塊實現了類似的功能,但是Scala
的trait
不要求特定的注解或特殊的包來實現依賴注入
-
-
- 導入實例成員
- 與導入類和對象的
import
使用方法一樣,可以導入單個成員,或者通過通配符_
導入所有成員 - 不會覆蓋私密性控制,只能導入可以正常訪問的字段和方法
- 與導入類和對象的
- 一種類類型,只能有不超過1個實例,也就是單例(
高級類型
- 暫略