1 Scala入門
scala Hello World
//HelloWorld.scala
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}
//run
scalac HelloWorld.scala //編譯
scala HelloWorld.scala //運(yùn)行
Scala變量
Scala變量
var myVar : String = 'Ingr' //聲明變量myVar
val myVal : String = 'Ingr' //聲明常量myVal
var myVar = 10; //在 Scala 中聲明變量和常量不一定要指明數(shù)據(jù)類型袱饭,在沒有指明數(shù)據(jù)類型的情況下尚粘,其數(shù)據(jù)類型是通過變量或常量的初始值推斷出來的于樟。所以兽愤,如果在沒有指明數(shù)據(jù)類型的情況下聲明變量或常量必須要給出其初始值,否則將會(huì)報(bào)錯(cuò)亚脆。
val xmax, ymax = 100 // Scala 支持多個(gè)變量的聲明,xmax, ymax都聲明為100
val ps = (40, "Foo") //pa: (Int, String) = (40,Foo),如果方法返回值是元組祷肯,我們可以使用 val 來聲明一個(gè)元組。
Scala字符串
var greeting:String = "Hello World!" //創(chuàng)建字符串
var greeting = "Hello World!" //不一定為字符串指定String類型市框,因?yàn)镾cala編譯器會(huì)自動(dòng)推斷出字符串的類型為String霞扬。
printf("浮點(diǎn)型變量為 " + "%f, 整型變量為 %d, 字符串為 " + " %s", floatVar, intVar, stringVar) //字符串格式化輸出
str.length() //獲取str字符串的長(zhǎng)度
str.format() //格式化字符串
str.split(String regex, int limit)) //根據(jù)匹配給定的正則表達(dá)式來拆分此字符串
str_1.concat(str_2) //使用concat()方法連接兩個(gè)字符串
Scala數(shù)組
// 數(shù)組聲明
var z:Array[String] = new Array[String](3) // z 聲明一個(gè)字符串類型的數(shù)組,數(shù)組長(zhǎng)度為 3 枫振,可存儲(chǔ) 3 個(gè)元素喻圃。
var z = new Array[string](3)
var myMatrix = ofDim[Int](3,3) // 聲明一個(gè)二維數(shù)組
//數(shù)組創(chuàng)建
z(0) = "Runoob"; z(1) = "Baidu"; z(4/2) = "Google" //先聲明z,再給z的每一個(gè)index賦值
var z = Array("Runoob", "Baidu", "Google") //直接通過賦值創(chuàng)建字符串
list = range(10, 20, 2) //使用了 range() 方法來生成一個(gè)區(qū)間范圍內(nèi)的數(shù)組
//遍歷數(shù)組
for( i <- 1 to (myList.length - 1) ) {
if (myList(i) > max) max = myList(i);
}
//數(shù)組合并
list_3 = concat(list_1, list_2)
scala List
??Scala 列表類似于數(shù)組粪滤,它們所有元素的類型都相同斧拍,但是它們也有所不同:列表是不可變的,值一旦被定義了就不能改變杖小,其次列表具有遞歸的結(jié)構(gòu)(也就是鏈接表結(jié)構(gòu))而數(shù)組不是肆汹。愚墓。
??列表的元素類型 T 可以寫成 List[T]。例如昂勉,以下列出了多種類型的列表:
// 創(chuàng)建List
val x = List(1,2,3,4) //定義整型List
val site: List[String] = List("Runoob", "Google", "Baidu") //創(chuàng)建字符串List
val empty: List[Nothing] = List()
val dim: List[List[Int]] = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))
val site = List.fill(3)("Runoob") //重復(fù)Runoob 3次;List.fill()方法創(chuàng)建一個(gè)指定重復(fù)數(shù)量的元素列表浪册,第一個(gè)參數(shù)為重復(fù)次數(shù),第二個(gè)元素為重復(fù)的元素硼啤。
val squares = List.tabulate(6)(n => n * n) //通過給定的函數(shù)創(chuàng)建 5 個(gè)元素;List.tabulate() 方法是通過給定的函數(shù)來創(chuàng)建列表议经。方法的第一個(gè)參數(shù)為元素的數(shù)量,可以是二維的谴返,第二個(gè)參數(shù)為指定的函數(shù)煞肾,我們通過指定的函數(shù)計(jì)算結(jié)果并返回值插入到列表中,起始值為 0嗓袱。
//創(chuàng)建List
val nums = 1 :: (2 :: (3 :: (4 :: Nil)))//創(chuàng)建列表的兩個(gè)基本單位是Nil和::
val site = "Runoob" :: ("Google" :: ("Baidu::Nil"))
val empty = Nil //Nil也可以表示為一個(gè)空列表
val dim = (1 :: (0 :: (0 :: Nil))) :: (0 :: (1 :: (0 :: Nil))) :: (0 :: (0 :: (1 :: Nil))) :: Nil
site.head //返回site list的第一個(gè)元素
site.tail //返回一個(gè)list籍救,包含了site list除了第一元素之外的其他元素
site.isEmpty //在list為空時(shí)返回true
site.reverse //
list_3 = list_1 ::: list_2 //合并list
list_3 = list_1.:::(list_2) //合并list
list_3 = List.concat(list_1, list_2) //合并list,將列表的順序反轉(zhuǎn);
scala 元組
??與列表一樣,元組也是不可變的渠抹,但與列表不同的是元組可以包含不同類型的元素蝙昙。
??元組的值是通過將單個(gè)的值包含在圓括號(hào)中構(gòu)成的。
// 元組的創(chuàng)建
val t = (1, 3,14, "Fred")
val t = new Tuple(1, 3,14, "Fred")
t._1 //使用 t._1 訪問第一個(gè)元素梧却, t._2 訪問第二個(gè)元素
t.productIterator.foreach{ i =>println("Value = " + i )} //使用 Tuple.productIterator() 方法來迭代輸出元組的所有元素
t.toString() //使用 Tuple.toString() 方法將元組的所有元素組合成一個(gè)字符串
t.swap() // 使用 Tuple.swap 方法來交換元組的元素
scala Set
??Scala Set(集合)是沒有重復(fù)的對(duì)象集合奇颠,所有的元素都是唯一的。
??Scala 集合分為可變的和不可變的集合放航。默認(rèn)情況下烈拒,Scala 使用的是不可變集合,如果你想使用可變集合广鳍,需要引用 scala.collection.mutable.Set 包荆几。
import scala.collection.mutable.Set // 可以在任何地方引入可變集合
val mutableSet = Set(1,2,3)
mutable += 5 //mutableSet每個(gè)元素+5
mutableSet.add(4) //mutableSet添加元素4;雖然可變Set和不可變Set都有添加或刪除元素的操作,但是有一個(gè)非常大的差別赊时。對(duì)不可變Set進(jìn)行操作吨铸,會(huì)產(chǎn)生一個(gè)新的set,原來的set并沒有改變祖秒,這與List一樣诞吱。 而對(duì)可變Set進(jìn)行操作,改變的是該Set本身竭缝,與ListBuffer類似狐胎。
mutableSet.remove(4) //mutableSet去除元素
mutableSet.head // 返回集合第一個(gè)元素
mutableSet.tail // 返回一個(gè)集合,包含除了第一元素之外的其他元素
mutableSet.isEmpty // 在集合為空時(shí)返回true
mutableSet.min // 使用 Set.min 方法來查找集合中的最小元素
mutableSet.max // 使用 Set.max 方法查找集合中的最大元素
set_3 = set_1 + set_2 //連接兩個(gè)集合
set_3 = set_1.++(set_2) //連接兩個(gè)集合
set_3 = set_1.&(set_2) //使用 Set.& 方法來查看兩個(gè)集合的交集元素歌馍。
set_3 = set_1.intersect(set_2) // 使用Set.intersect 方法來查看兩個(gè)集合的交集元素。
scala Map
??Map(映射)是一種可迭代的鍵值對(duì)(key/value)結(jié)構(gòu)晕鹊。
??所有的值都可以通過鍵來獲取松却。
??Map 中的鍵都是唯一的暴浦。
??Map 也叫哈希表(Hash tables)。
??Map 有兩種類型晓锻,可變與不可變歌焦,區(qū)別在于可變對(duì)象可以修改它,而不可變對(duì)象不可以砚哆。
??默認(rèn)情況下 Scala 使用不可變 Map独撇。如果你需要使用可變集合,你需要顯式的引入 import scala.collection.mutable.Map 類
??在 Scala 中 你可以同時(shí)使用可變與不可變 Map躁锁,不可變的直接使用 Map纷铣,可變的使用 mutable.Map。
//創(chuàng)建Map
var A:Map[Char,Int] = Map() // 空哈希表战转,鍵為字符串搜立,值為整型
val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF") // Map 鍵值對(duì)演示
A += ('I' -> 1) //Map中添加 key-value 對(duì)
A.keys //返回 Map 所有的鍵(key)
A.values //返回 Map 所有的值(value)
A.isEmpty //在 Map 為空時(shí)返回true
A.contains() //使用 Map.contains 方法來查看 Map 中是否存在指定的 Key
map_3 = map_1 ++ map_2
map_3 = map_1.++(map_2)
// map的遍歷
// foreach 循環(huán)輸出 Map 中的 keys 和 values
sites.keys.foreach{ i =>
print( "Key = " + i )
println(" Value = " + sites(i) )}
scala Option
??Scala Option(選項(xiàng))類型用來表示一個(gè)值是可選的(有值或無(wú)值)。
??Option[T] 是一個(gè)類型為 T 的可選值的容器: 如果值存在槐秧, Option[T] 就是一個(gè) Some[T] 啄踊,如果不存在, Option[T] 就是對(duì)象 None 刁标。
??Option 有兩個(gè)子類別颠通,一個(gè)是 Some,一個(gè)是 None膀懈,當(dāng)他回傳 Some 的時(shí)候顿锰,代表這個(gè)函式成功地給了你一個(gè) String,而你可以透過 get() 這個(gè)函式拿到那個(gè) String吏砂,如果他返回的是 None撵儿,則代表沒有字符串可以給你。
// Option的定義
val myMap: Map[String, String] = Map("key1" -> "value")
val option_1: Option[String] = myMap.get("key1")
val option_2: Option[String] = myMap.get("key2")
println(option_1) // Some("value1")
println(option_2) // None
option_1.getOrElse() //使用 getOrElse()方法來獲取元組中存在的元素或者使用其默認(rèn)的值
option_1.isEmpty() //使用 isEmpty() 方法來檢測(cè)元組中的元素是否為 None
Scala Iterator(迭代器)
??Scala Iterator(迭代器)不是一個(gè)集合狐血,它是一種用于訪問集合的方法淀歇。
??迭代器 it 的兩個(gè)基本操作是 next 和 hasNext。
??調(diào)用 it.next() 會(huì)返回迭代器的下一個(gè)元素匈织,并且更新迭代器的狀態(tài)浪默。
??調(diào)用 it.hasNext() 用于檢測(cè)集合中是否還有元素。
??讓迭代器 it 逐個(gè)返回所有元素最簡(jiǎn)單的方法是使用 while 循環(huán):
val it = Iterator("Baidu", "Google", "Runoob", "Taobao")
while (it.hasNext){
println(it.next())
}
it.max // 從迭代器it中查找最大元素
it.min // 從迭代器中查找最小元素
it.size // 查看迭代器中的元素個(gè)數(shù)
it.length //查看迭代器中的元素個(gè)數(shù)
3 Scala語(yǔ)句
if else語(yǔ)句
if(布爾表達(dá)式){
if(){
//嵌套模塊
***
}
}else if(){
***
}else {
***
}
循環(huán)語(yǔ)句
// while 循環(huán)
while(condition)
{
statement(s);
}
// do ... while 循環(huán)
do {
statement(s);
} while( condition );
//for循環(huán)
//Range 可以是一個(gè)數(shù)字區(qū)間表示 i to j 缀匕,或者 i until j纳决。左箭頭 <- 用于為變量 x 賦值。
for( var x <- Range ){
statement(s);
}
// 在 for 循環(huán) 中你可以使用分號(hào) (;) 來設(shè)置多個(gè)區(qū)間乡小,它將迭代給定區(qū)間所有的可能值阔加。
for( a <- 1 to 3; b <- 1 to 3){
println( "Value of a: " + a );
println( "Value of b: " + b );
//for 循環(huán)集合
for( var x <- List ){
statement(s);
}
val numList = List(1,2,3,4,5,6);
for( a <- numList ){
println( "Value of a: " + a );
//for 循環(huán)過濾
//Scala 可以使用一個(gè)或多個(gè) if 語(yǔ)句來過濾一些元素。使用分號(hào)(;)來為表達(dá)式添加一個(gè)或多個(gè)的過濾條件满钟。
for( var x <- List
if condition1; if condition2...
){
statement(s);
//for 使用 yield
//可以將 for 循環(huán)的返回值作為一個(gè)變量存儲(chǔ)胜榔,注意大括號(hào)中用于保存變量和條件胳喷,retVal 是變量, 循環(huán)中的 yield 會(huì)把當(dāng)前的元素記下來夭织,保存在集合中吭露,循環(huán)結(jié)束后將返回該集合。
var retVal = for{ var x <- List
if condition1; if condition2...
}yield x
Scala 方法與函數(shù)
??Scala 有方法與函數(shù)尊惰,二者在語(yǔ)義上的區(qū)別很小讲竿。Scala 方法是類的一部分,而函數(shù)是一個(gè)對(duì)象可以賦值給一個(gè)變量弄屡。換句話來說在類中定義的函數(shù)即是方法题禀。
??Scala 中的方法跟 Java 的類似,方法是組成類的一部分琢岩。
??Scala 中的函數(shù)則是一個(gè)完整的對(duì)象投剥,Scala 中的函數(shù)其實(shí)就是繼承了 Trait 的類的對(duì)象。
??Scala 中使用 val 語(yǔ)句可以定義函數(shù)担孔,def 語(yǔ)句定義方法江锨。
class Test{
def m(x:Int) = x + 3
val f = (x:Int) => x + 3
}
// 方法聲明
def functionName([參數(shù)列表]):[return type]
// 方法定義
def functionName([參數(shù)列表]):[return type] = {
function body
return [expr]
}
//如果你不寫等于號(hào)和方法主體,那么方法會(huì)被隱式聲明為抽象(abstract)糕篇,包含它的類型于是也是一個(gè)抽象類型啄育。
//return type 可以是任意合法的 Scala 數(shù)據(jù)類型。參數(shù)列表中的參數(shù)可以使用逗號(hào)分隔拌消。
//如果方法沒有返回值挑豌,可以返回為 Unit,這個(gè)類似于 Java 的 void, 實(shí)例如下:
// 方法調(diào)用
functionName(參數(shù)列表) //調(diào)用方法的標(biāo)準(zhǔn)格式
[instance.]functionName( 參數(shù)列表 ) //如果方法使用了實(shí)例的對(duì)象來調(diào)用墩崩,我們可以使用類似java的格式 (使用 . 號(hào))氓英;
Scala 閉包
??閉包是一個(gè)函數(shù),返回值依賴于聲明在函數(shù)外部的一個(gè)或多個(gè)變量鹦筹。
??閉包通常來講可以簡(jiǎn)單的認(rèn)為是可以訪問一個(gè)函數(shù)里面局部變量的另外一個(gè)函數(shù)铝阐。
val multiplier = (i:Int) => i * 10 // 函數(shù)體內(nèi)有一個(gè)變量 i,它作為函數(shù)的一個(gè)參數(shù)铐拐。
val multiplier = (i:Int) => i * factor //在 multiplier 中有兩個(gè)變量:i 和 factor徘键。其中的一個(gè) i 是函數(shù)的形式參數(shù),在 multiplier 函數(shù)被調(diào)用時(shí)遍蟋,i 被賦予一個(gè)新的值吹害。然而,factor不是形式參數(shù)虚青,而是自由變量;
4 Scala 類和對(duì)象
??類是對(duì)象的抽象它呀,而對(duì)象是類的具體實(shí)例。類是抽象的,不占用內(nèi)存钟些,而對(duì)象是具體的烟号,占用存儲(chǔ)空間。類是用于創(chuàng)建對(duì)象的藍(lán)圖政恍,它是一個(gè)定義包括在特定類型的對(duì)象中的方法和變量的軟件模板。
??我們可以使用 new 關(guān)鍵字來創(chuàng)建類的對(duì)象达传,實(shí)例如下:
import java.io._
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 的坐標(biāo)點(diǎn): " + x);
println ("y 的坐標(biāo)點(diǎn): " + y);
}
}
object Test {
def main(args: Array[String]) {
val pt = new Point(10, 20);
// 移到一個(gè)新的位置
pt.move(10, 10);
}
}
4.1 Scala 繼承
??Scala繼承一個(gè)基類跟Java很相似, 但我們需要注意以下幾點(diǎn):
??1篙耗、重寫一個(gè)非抽象方法必須使用override修飾符。
??2宪赶、只有主構(gòu)造函數(shù)才可以往基類的構(gòu)造函數(shù)里寫參數(shù)宗弯。
??3、在子類中重寫超類的抽象方法時(shí)搂妻,你不需要使用override關(guān)鍵字蒙保。
import java.io._
class Point(val xc: Int, val yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
println ("x 的坐標(biāo)點(diǎn) : " + x);
println ("y 的坐標(biāo)點(diǎn) : " + y);
}
}
class Location(override val xc: Int, override val yc: Int,
val zc :Int) extends Point(xc, yc){
var z: Int = zc
def move(dx: Int, dy: Int, dz: Int) {
x = x + dx
y = y + dy
z = z + dz
println ("x 的坐標(biāo)點(diǎn) : " + x);
println ("y 的坐標(biāo)點(diǎn) : " + y);
println ("z 的坐標(biāo)點(diǎn) : " + z);
}
}
object Test {
def main(args: Array[String]) {
val loc = new Location(10, 20, 15);
// 移到一個(gè)新的位置
loc.move(10, 10, 5);
}
}
4.2 Scala 單例對(duì)象
??在 Scala 中,是沒有 static 這個(gè)東西的欲主,但是它也為我們提供了單例模式的實(shí)現(xiàn)方法邓厕,那就是使用關(guān)鍵字 object。
??Scala 中使用單例模式時(shí)扁瓢,除了定義的類之外详恼,還要定義一個(gè)同名的 object 對(duì)象,它和類的區(qū)別是引几,object對(duì)象不能帶參數(shù)昧互。
??當(dāng)單例對(duì)象與某個(gè)類共享同一個(gè)名稱時(shí),他被稱作是這個(gè)類的伴生對(duì)象:companion object伟桅。你必須在同一個(gè)源文件里定義類和它的伴生對(duì)象敞掘。類被稱為是這個(gè)單例對(duì)象的伴生類:companion class。類和它的伴生對(duì)象可以互相訪問其私有成員楣铁。
??單例對(duì)象實(shí)例:
import java.io._
class Point(val xc: Int, val yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
}
}
object Test {
def main(args: Array[String]) {
val point = new Point(10, 20)
printPoint
def printPoint{
println ("x 的坐標(biāo)點(diǎn) : " + point.x);
println ("y 的坐標(biāo)點(diǎn) : " + point.y);
}
}
}
??伴生對(duì)象實(shí)例:
/* 文件名:Marker.scala
* author:菜鳥教程
* url:www.runoob.com
*/
// 私有構(gòu)造方法
class Marker private(val color:String) {
println("創(chuàng)建" + this)
override def toString(): String = "顏色標(biāo)記:"+ color
}
// 伴生對(duì)象玖雁,與類共享名字,可以訪問類的私有屬性和方法
object Marker{
private val markers: Map[String, Marker] = Map(
"red" -> new Marker("red"),
"blue" -> new Marker("blue"),
"green" -> new Marker("green")
)
def apply(color:String) = {
if(markers.contains(color)) markers(color) else null
}
def getMarker(color:String) = {
if(markers.contains(color)) markers(color) else null
}
def main(args: Array[String]) {
println(Marker("red"))
// 單例函數(shù)調(diào)用民褂,省略了.(點(diǎn))符號(hào)
println(Marker getMarker "blue")
}
}
5 Scala Trait(特征)
??Scala Trait(特征) 相當(dāng)于 Java 的接口茄菊,實(shí)際上它比接口還功能強(qiáng)大。
??與接口不同的是赊堪,它還可以定義屬性和方法的實(shí)現(xiàn)面殖。
??一般情況下Scala的類只能夠繼承單一父類,但是如果是 Trait(特征) 的話就可以繼承多個(gè)哭廉,從結(jié)果來看就是實(shí)現(xiàn)了多重繼承脊僚。
??Trait(特征) 定義的方式與類類似,但它使用的關(guān)鍵字是 trait
/* 文件名:Test.scala
* author:菜鳥教程
* url:www.runoob.com
*/
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}
class Point(xc: Int, yc: Int) extends Equal {
var x: Int = xc
var y: Int = yc
def isEqual(obj: Any) =
obj.isInstanceOf[Point] &&
obj.asInstanceOf[Point].x == x
}
object Test {
def main(args: Array[String]) {
val p1 = new Point(2, 3)
val p2 = new Point(2, 4)
val p3 = new Point(3, 3)
println(p1.isNotEqual(p2))
println(p1.isNotEqual(p3))
println(p1.isNotEqual(2))
}
}
特征構(gòu)造順序
??特征也可以有構(gòu)造器,由字段的初始化和其他特征體中的語(yǔ)句構(gòu)成辽幌。這些語(yǔ)句在任何混入該特征的對(duì)象在構(gòu)造時(shí)都會(huì)被執(zhí)行增淹。
??構(gòu)造器的執(zhí)行順序:
??調(diào)用超類的構(gòu)造器;
??特征構(gòu)造器在超類構(gòu)造器之后乌企、類構(gòu)造器之前執(zhí)行虑润;
??特征由左到右被構(gòu)造;
??每個(gè)特征當(dāng)中加酵,父特征先被構(gòu)造拳喻;
??如果多個(gè)特征共有一個(gè)父特征,父特征不會(huì)被重復(fù)構(gòu)造
??所有特征被構(gòu)造完畢猪腕,子類被構(gòu)造冗澈。
??構(gòu)造器的順序是類的線性化的反向。線性化是描述某個(gè)類型的所有超類型的一種技術(shù)規(guī)格陋葡。
Scala 文件IO
//寫入文件
val writer = new PrintWriter(new File("test.txt" ))
writer.write("菜鳥教程")
writer.close()
//讀取文件
Source.fromFile("test.txt" ).foreach{
print
}
//讀取屏幕輸入
val line = StdIn.readLine()