文章目錄
- Scala 與 Java 的最大區別是:Scala 語句末尾的分號 ; 是可選的。
- 大小寫敏感
- 類名第一個字母大寫
- 方法名第一個字母小寫
- 定義包
package
- 引入包
import java.awt._ // 引入包內所有成員
基本數據類型和操作
基本數據類型
Scala的數據類型包括:Byte、Char、Short、Int、Long、Float、Double和 Boolean。對於字符串,Scala用java.lang.String 類來表示字符串。
操作符
-
在Scala中,可以使用加(+)、減(-) 、乘(*) 、除(/) 、餘數(%)等操作 符,而且,這些操作符就是方法。例如,5 + 3和(5).+(3)是等價的。
-
在Scala中並沒有提供++和–操作符。
富包裝類
-
對於基本數據類型,除了以上提到的各種操作符外,Scala 還提供了許多常用運算的方法,只是這些方法不是在基本類 裏面定義,還是被封裝到一個對應的富包裝類中
-
每個基本類型都有一個對應的富包裝類,例如Int有一個 RichInt類、String有一個RichString類,這些類位於包 scala.runtime中
-
當對一個基本數據類型的對象調用其富包裝類提供的方法, Scala會自動通過隱式轉換將該對象轉換爲對應的富包裝類 型,然後再調用相應的方法。例如:3 max 5
Range
可以用一下命令來產生for循環時的數值序列:
1 to 5
1 util5
1 to 10 by 2
輸入
import scala.io._. // read_xxx 在這個包中
var i = readInt()
var l = readLine()
var c = readChar()
var b = readBoolean()
輸出
print()
、println()
和printf()
讀寫文件
- Scala 進行文件寫操作,直接用的都是 java中 的 I/O 類 (java.io.File)
import java.io._
object Test {
def main(args: Array[String]) {
val writer = new PrintWriter(new File("test.txt" ))
writer.write("菜鳥教程")
writer.close()
}
}
- 可以使用Scala.io.Source的getLines方法實現對文件中所 有行的讀取
import scala.io.Source
object Test {
def main(args: Array[String]) {
println("文件內容爲:" )
// 1.
Source.fromFile("test.txt" ).foreach{
print
}
// 2.返回結果是個迭代器
Source.fromFile("test.txt" ).getlines
}
}
控制結構
條件: if
if(布爾表達式 1){
// 如果布爾表達式 1 爲 true 則執行該語句塊
}else if(布爾表達式 2){
// 如果布爾表達式 2 爲 true 則執行該語句塊
}else if(布爾表達式 3){
// 如果布爾表達式 3 爲 true 則執行該語句塊
}else {
// 如果以上條件都爲 false 執行該語句塊
}
循環:While/do…while/for
for( a <- 1 to 10){
println( "Value of a: " + a );
}
for( a <- 1 to 3; b <- 1 to 3){
println( "Value of a: " + a );
println( "Value of b: " + b );
}
val numList = List(1,2,3,4,5,6);
for( a <- numList ){
println( "Value of a: " + a );
}
//for 循環過濾
for( a <- numList if a != 3; if a < 8 ){
println( "Value of a: " + a );
}
//for 使用 yield
var retVal = for{ a <- numList
if a != 3; if a < 8
}yield a
數據結構
容器(Collection)
- Scala提供了一套豐富的容器(collection)庫,包括列表 (List)、數組(Array)、集合(Set)、映射(Map)等
- 根據容器中元素的組織方式和操作方式,可以區分爲有序 和無序、可變和不可變等不同的容器類別
- Scala用了三個包來組織容器類,分別是scala.collection 、 scala.collection.mutable(可變集)和scala.collection.immutable(不可變集)
- 它爲所有的容器類定義了公用的
foreach
方法,用於對容器元素進行遍歷操作
列表(List):
Scala 列表類似於數組,它們所有元素的類型都相同,但是它們也有所不同:列表是不可變的,值一旦被定義了就不能改變,其次列表 具有遞歸的結構(也就是鏈接表結構)而數組不是。。
幾個要知道的符號:
- 列表的元素類型 T 可以寫成
List[T]
- 構造列表的兩個基本單位是 Nil 和 ::。Nil 也可以表示爲一個空列表。
定義
有兩種方式:
// 字符串列表
val site: List[String] = List("Runoob", "Google", "Baidu")
val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil))
// 空列表
val empty: List[Nothing] = List()
val empty = Nil
// 二維列表
val dim: List[List[Int]] =
List(
List(1, 0, 0),
List(0, 1, 0),
List(0, 0, 1)
)
val dim = (1 :: (0 :: (0 :: Nil))) ::
(0 :: (1 :: (0 :: Nil))) ::
(0 :: (0 :: (1 :: Nil))) :: Nil
列表基本操作
head
返回列表第一個元素tail
返回一個列表,包含除了第一元素之外的其他元素isEmpty
在列表爲空時返回true
println( "第一網站是 : " + site.head )
println( "最後一個網站是 : " + site.tail )
println( "查看列表 site 是否爲空 : " + site.isEmpty )
連接列表
可以使用 ::: 運算符或 List.::😦) 方法或 List.concat() 方法來連接兩個或多個列表。
// 使用 ::: 運算符
var fruit = site1 ::: site2
println( "site1 ::: site2 : " + fruit )
// 使用 List.:::() 方法
fruit = site1.:::(site2)
println( "site1.:::(site2) : " + fruit )
// 使用 concat 方法
fruit = List.concat(site1, site2)
println( "List.concat(site1, site2) : " + fruit )
Scala List 常用方法
-
List.fill(): 我們可以使用 List.fill() 方法來創建一個指定重複數量的元素列表:
val site = List.fill(3)("Runoob") // 重複 Runoob 3次 println( "site : " + site ) val num = List.fill(10)(2) // 重複元素 2, 10 次 println( "num : " + num )
-
List.tabulate() 方法是通過給定的函數來創建列表。
方法的第一個參數爲元素的數量,可以是二維的,第二個參數爲指定的函數,我們通過指定的函數計算結果並返回值插入到列表中,起始值爲 0,實例如下:
// 通過給定的函數創建 5 個元素 val squares = List.tabulate(6)(n => n * n) println( "一維 : " + squares ) // 創建二維列表 val mul = List.tabulate( 4,5 )( _ * _ ) println( "多維 : " + mul )
輸出:
一維 : List(0, 1, 4, 9, 16, 25) 多維 : List(List(0, 0, 0, 0, 0), List(0, 1, 2, 3, 4), List(0, 2, 4, 6, 8), List(0, 3, 6, 9, 12))
// +: 爲列表添加元素 (:朝着list)
"xxx"+:site // 返回:List(xxx, Runoob, Google, Baidu)
// :+
site :+ "xxx" // 返回 List[String] = List(Runoob, Google, Baidu, xxx)
// :: 在列表開頭添加元素
"xxx"::site // 返回:List(xxx, Runoob, Google, Baidu)
// :::在列表開頭添加指定列表的元素
site ::: nums // val res35: List[Any] = List(Runoob, Google, Baidu, 1, 3, 2)
// ++ 拼接
site++nums // 返回:val res34: List[Any] = List(Runoob, Google, Baidu, 1, 3, 2)
// ++:和:++
site :++ nums // val res31: List[Any] = List(Runoob, Google, Baidu, 1, 3, 2)
site ++: nums // val res29: List[Any] = List(Runoob, Google, Baidu, 1, 3, 2)
site.apply(2) // apply 通過列表索引獲取元素
// val res42: String = Baidu
site.contains("baidu")
// val res43: Boolean = false
val nums = List(1,1,2,3); nums.distinct
// val res45: List[Int] = List(1, 2, 3)
nums.exists(x=>x>1) // 判斷列表中指定條件的元素是否存在。
// val res47: Boolean = true
nums.filter(x=>x>1) // 輸出符號指定條件的所有元素。
//val res48: List[Int] = List(2, 3)
site.foreach(print(_)) // 將函數應用到列表的所有元素
// RunoobGoogleBaidu
site.indexOf("Baidu")
//val res69: Int = 2
site.map(x=>x+"xxx")
// val res71: List[String] = List(Runoobxxx, Googlexxx, Baiduxxx)
site.mkString(";") // 使用分隔符將列表所有元素作爲字符串顯示
// val res74: String = Runoob;Google;Baidu
site.mkString // 列表所有元素作爲字符串顯示
// val res75: String = RunoobGoogleBaidu
site.reverse
// val res77: List[String] = List(Baidu, Google, Runoob)
site.toString()
// val res86: String = List(Runoob, Google, Baidu)
集合(Set)
- 集合包括可變集和不可變集,
- 默認是不可變的,如果要聲明一個可變集,則需要提前引入scala.collection.mutable.Set
import scala.collection.mutable.Set // 可以在任何地方引入 可變集合
val mutableSet = Set(1,2,3)
// val mutableSet: scala.collection.mutable.Set[Int] = HashSet(1, 2, 3)
mutableSet.add(4)
mutableSet.remove(1)
num1 & num2 // 交集 或者.&或.intersect 取交集
// val res97: scala.collection.mutable.Set[Int] = HashSet(20, 9)
num1 &~ num2 // 差集
//val res98: scala.collection.mutable.Set[Int] = HashSet(5, 6, 45, 30)
num2 &~ num1 // 差集
//val res99: scala.collection.mutable.Set[Int] = HashSet(50, 35, 55, 60)
num1 ++ num2 // 連接集合
// val res101: scala.collection.mutable.Set[Int] = HashSet(35, 5, 6, 9, 45, 50, 20, 55, 60, 30)
映射(Map)
- Map 有兩種類型,可變與不可變,區別在於可變對象可以修改它,而不可變對象不可以。
- 默認情況下 Scala 使用不可變 Map。如果你需要使用可變集合,你需要顯式的引入 import scala.collection.mutable.Map 類
- 更多參考API
// 空哈希表,鍵爲字符串,值爲整型
var A:Map[Char,Int] = Map()
// Map 鍵值對演示
val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF")
println( "colors 中的鍵爲 : " + colors.keys )
println( "colors 中的值爲 : " + colors.values )
println( "檢測 colors 是否爲空 : " + colors.isEmpty )
colors.keys.foreach{ i =>
print( "Key = " + i )
println(" Value = " + colors(i) )}
colors.toSet
// val res106: scala.collection.immutable.Set[(String, String)] = Set((red,#FF0000), (azure,#F0FFFF))
迭代器(Iterator)
- 在Scala中,迭代器(Iterator)不是一個集合,但是,提供了 訪問集合的一種方法
- 迭代器包含兩個基本操作:next和hasNext。next可以返回迭代器的下一個元素,hasNext用於檢測是否還有下一個元素
val it = Iterator("Baidu", "Google", "Runoob", "Taobao")
while (it.hasNext){
println(it.next())
}
it.size
it.length
數組(Array)
- 數組是一種可變的、可索引的、元素具有相同類型的數據集合,它是各種高 級語言中最常用的數據結構。
- Scala提供了參數化類型的通用數組類Array[T], 其中T可以是任意的Scala類型,可以通過顯式指定類型或者通過隱式推斷來 實例化一個數組。
- Array提供了函數ofDim來定義二維和三維數組
- 採用Array類型定義的數組屬於定長數組,其數組長度在初始化後就不能改變。如果要定義變長數組,需要使用ArrayBuffer參數類型,其位於包 scala.collection.mutable中。
- 更多參考
import Array._
// 定義1
var z = Array("Runoob", "Baidu", "Google")
// 定義2
var z = new Array[String](3)
z(0) = "Runoob"; z(1) = "Baidu"; z(4/2) = "Google"
// 輸出所有數組元素
for ( x <- myList ) {
println( x )
}
myList.length
// 多維數組,通過ofDim定義
var myMatrix = ofDim[Int](3,3)
for (i <- 0 to 2) {
for ( j <- 0 to 2) {
myMatrix(i)(j) = j;
}
}
// 合併數組
var myList3 = concat( myList1, myList2)
元組(Tuple)
- 與列表一樣,元組也是不可變的,但與列表不同的是元組可以包含不同類型的元素。
- 目前 Scala 支持的元組最大長度爲 22。
- 我們可以使用 t._1 訪問第一個元素, t._2 訪問第二個元素
val t = (1, 3.14, "Fred")
val t = (4,3,2,1)
val sum = t._1 + t._2 + t._3 + t._4 // 訪問元祖元素;返回10
t.productIterator.foreach{ i =>println("Value = " + i )} //Tuple.productIterator() 迭代輸出元組的所有元素
Option
- Scala Option(選項)類型用來表示一個值是可選的(有值或無值)。
- Option[T] 是一個類型爲 T 的可選值的容器: 如果值存在, Option[T] 就是一個 Some[T] ,如果不存在, Option[T] 就是對象 None 。
- 可以使用 getOrElse() 方法來獲取元組中存在的元素或者使用其默認的值,
val myMap: Map[String, String] = Map("key1" -> "value")
val value1: Option[String] = myMap.get("key1") // Some("value1")
val value2: Option[String] = myMap.get("key2") // None
def show(x: Option[String]) = x match {
case Some(s) => s
case None => "?"
}
print(show(value1) ) // value
print(show(value2) ) // ?
value1.getOrElse(0) // value
value2.getOrElse(0) // 0
value1.filter(_=="value")
// val res6: Option[String] = Some(value)
面向對象編程基礎
Scala 方法與函數
- Scala 有方法與函數,二者在語義上的區別很小。Scala 方法是類的一部分,而函數是一個對象可以賦值給一個變量。換句話來說在類中定義的函數即是方法。
- Scala 中的函數則是一個完整的對象,Scala 中的函數其實就是繼承了 Trait 的類的對象。
- Scala 中使用 val 語句可以定義函數,def 語句定義方法。
方法
- 方法定義由一個 def 關鍵字開始,緊接着是可選的參數列表,一個冒號 : 和方法的返回類型,一個等於號 = ,最後是方法的主體。
- 如果方法沒有返回值,可以返回爲 Unit,這個類似於 Java 的 void,
def functionName ([參數列表]) : [return type] // 聲明
def functionName ([參數列表]) : [return type] = { // 定義
function body
return [expr]
}
// 舉例
object Test {
def main(args: Array[String]) {
println( "Returned Value : " + addInt(5,7) );
}
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
類
class Point(xc: Int, yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
println ("x 的座標點: " + x);
println ("y 的座標點: " + y);
}
def increment():Unit = {x += 1}
def current(): Int = {value} // 如果操作語句只有一句
}
object Test {
def main(args: Array[String]) {
val pt = new Point(10, 20);
// 移到一個新的位置
pt.move(10, 10);
}
}
對象
單例對象
- Scala並沒有提供Java那樣的靜態方法或靜態字段,但是,可以採用 object關鍵字實現單例對象,具備和Java靜態方法同樣的功能。
伴生對象
- 在Java中,我們經常需要用到同時包含實例方法和靜態 方法的類,在Scala中可以通過伴生對象來實現。
- 當單例對象與某個類具有相同的名稱時,它被稱爲這個 類的“伴生對象”。
- 類和它的伴生對象必須存在於同一個文件中,而且可以 相互訪問私有成員(字段和方法)。
繼承
Scala繼承一個基類跟Java很相似, 但我們需要注意以下幾點:
- 1、重寫一個非抽象方法必須使用override修飾符。
- 2、只有主構造函數纔可以往基類的構造函數裏寫參數。
- 3、在子類中重寫超類的抽象方法時,不需要使用override關鍵字。
特質
模式匹配
函數式編程
實例WordCount:
import java.io.File
import scala.io.Source
object WordCount{
def main(args:Array[String]):Unit={
val dirfile=new File("wordCount")
val files = dirfile.listFiles
for(file <- files) print(file)
val listFiles = files.toList
val wordsMap = scala.collection.mutable.Map[String,Int]()
listFiles.foreach(file => Source.fromFile(file).getLines().foreach(line => line.split(" ").foreach(
word => {
if(wordsMap.contains(word)){
wordsMap(word) += 1
}else{
wordsMap+=(word->1)
}
}
)))
println(wordsMap)
for((key,value)<-wordsMap) print(key + ": " + value)
}
}