Scala能夠是一種面向對象的語言,每一個值均可以是對象。javascript
Scala提供了輕量級的語法用以定義匿名函數,支持高階函數,容許嵌套多層函數,並支持柯里化。php
Scala具有類型系統,經過編譯時檢查,保證代碼的安全性和一致性。css
Scala提供了許多獨特的語言機制,能夠以庫的形式輕易無縫添加新的語言結構:html
Scala使用Actor做爲其併發模型,Actor是相似線程的實體,經過郵箱發收消息。Actor能夠複用線程,所以在程序中可使用數百萬個Actor,而線程只能建立數千個。在2.10以後的版本中,使用Akka做爲其默認Actor實現。java
Scala 使用 package 關鍵字定義包,在Scala將代碼定義到某個包中有兩種方式:python
和 Java 同樣,在文件的頭定義包名,這種方法就後續全部代碼都放在該包中。 好比:nginx
package com.runoob class HelloWorld{ }
有些相似 C#,如:面試
package com.runoob { class HelloWorld{ } }
第二種方法,能夠在一個文件中定義多個包。正則表達式
Scala 使用 import 關鍵字引用包。sql
import java.awt.Color // 引入Color import java.awt._ // 引入包內全部成員 def handler(evt: event.ActionEvent) { // java.awt.event.ActionEvent ... // 由於引入了java.awt,因此能夠省去前面的部分 }
import語句能夠出如今任何地方,而不是隻能在文件頂部。import的效果從開始延伸到語句塊的結束。這能夠大幅減小名稱衝突的可能性。
若是想要引入包中的幾個成員,可使用selector語法糖(選取器):
import java.awt.{Color, Font} // 重命名成員 import java.util.{HashMap => JavaHashMap} // 隱藏成員 import java.util.{HashMap => _, _} // 引入了util包的全部成員,可是HashMap被隱藏了
注意
:默認狀況下,Scala 總會引入 java.lang._ 、 scala._ 和 Predef._,這裏也就解釋了,爲何以scala開頭的包,在使用時都是省去scala.的。
Scala的數據類型和Java差很少,如下是和Java不一樣之處.
數據類型 | 描述 |
---|---|
java... | 和java同樣,8種基本類型... |
Unit | 表示無值,和其餘語言中void等同。用做不返回任何結果的方法的結果類型。Unit只有一個實例值,寫成()。 |
Null | null 或空引用 |
Nothing | Nothing類型在Scala的類層級的最低端;它是任何其餘類型的子類型。 |
Any | Any是全部其餘類的超類 |
AnyRef | AnyRef類是Scala裏全部引用類(reference class)的基類 |
上表中列出的數據類型都是對象,也就是說scala沒有java中的原生類型。在scala是能夠對數字等基礎類型調用方法的。
關於Scala的類型關係,能夠看個人另外一篇文章Scala的類層級講解
符號字面量 'x 是表達式 scala.Symbol("x") 的簡寫;
val foo = """菜鳥教程 www.runoob.com www.w3cschool.cc www.runnoob.com 以上三個地址都能訪問"""
變量是一種使用方便的佔位符,用於引用計算機內存地址,變量建立後會佔用必定的內存空間。
在 Scala 中,使用關鍵詞 "var" 聲明變量,使用關鍵詞 "val" 聲明常量。
var myVar : String = "Foo" val myVal : String = "Foo"
在 Scala 中聲明變量和常量不必定要指明數據類型,在沒有指明數據類型的狀況下,其數據類型是經過變量或常量的初始值推斷出來的。
++因此,若是在沒有指明數據類型的狀況下聲明變量或常量必需要給出其初始值,不然將會報錯。++
val xmax, ymax = 100 // xmax, ymax都聲明爲100
分別有:private,protected,public(默認)。
Scala 中的 private 限定符,比 Java 更嚴格,在嵌套類狀況下,外層類甚至不能訪問被嵌套類的私有成員。
class Outer{ class Inner{ private def f(){ println("f") } class InnerMost{ f() // 正確 } } (new Inner).f() //錯誤 }
對保護(Protected)成員的訪問比 java 更嚴格一些。
由於它只容許保護成員在定義了該成員的的類的子類中被訪問,同包不可訪問。
package p{ class Super{ protected def f() { println("f") } } class Sub extends Super{ f() } class Other{ (new Super).f() //錯誤 } }
若是沒有指定任何的修飾符,則默認爲 public。這樣的成員在任何地方均可以被訪問。
Scala中,訪問修飾符能夠經過使用限定詞強調。格式爲:
private[x] 或 protected[x]
這裏的x指代某個所屬的包、類或單例對象。若是寫成private[x],讀做"這個成員除了對[…]中的類或[…]中的包中的類及它們的伴生對象可見外,對其它全部類都是private。
這種技巧在橫跨了若干包的大型項目中很是有用,它容許你定義一些在你項目的若干子包中可見但對於項目外部的客戶卻始終不可見的東西。
package bobsrocckets{ package navigation{ private[bobsrockets] class Navigator{ protected[navigation] def useStarChart(){} class LegOfJourney{ private[Navigator] val distance = 100 } private[this] var speed = 200 } } package launch{ import navigation._ object Vehicle{ private[launch] val guide = new Navigator } } }
上述例子中,類Navigator被標記爲private[bobsrockets]就是說這個類對包含在bobsrockets包裏的全部的類和對象可見。
好比說,從Vehicle對象裏對Navigator的訪問是被容許的,由於對象Vehicle包含在包launch中,而launch包在bobsrockets中,相反,全部在包bobsrockets以外的代碼都不能訪問類Navigator。
和java同樣+ , - , * , / , %
和java同樣 == , != , > , < , >= , <=
和java同樣&& , || , !
和java同樣& , | , ^ , ~ , << , >> , >>>
~ 按位取反
無符號右移
和java同樣
和java同樣,支持嵌套同時有返回值.
和java徹底同樣,支持嵌套.
Scala 有函數和方法,兩者在語義上的區別很小。
Scala 方法是類的一部分,而函數是一個對象能夠賦值給一個變量。換句話來講在類中定義的函數便是方法。
咱們能夠在任何地方定義函數,甚至能夠在函數內定義函數(內嵌函數)。更重要的一點是 Scala 函數名能夠有如下特殊字符:+, ++, ~, &,-, -- , \, /, :
等。
def functionName ([參數列表]) : [return type]
若是你不寫等於號和方法主體,那麼方法會被隱式聲明爲"抽象(abstract)",包含它的類也變成一個抽象類。
def functionName ([參數列表]) : [return type] = { function body return [expr] }
以下,一個求加法的函數:
object add{
def addInt( a:Int, b:Int ) : Int = { var sum:Int = 0 sum = a + b return sum } }
若是函數沒有返回值,能夠返回爲 Unit,這個相似於 Java 的 void.
Scala的靈活性,使的函數定義的方法多種多樣:
一、規規矩矩的寫法,帶有等號、大括號和返回值類型的形式
def myFunc(p1: Int) : Int = { //something } def myFunc(p1: Int) : Unit = { //something }
二、非unit返回值的情形下,省略返回值,讓程序根據代碼塊,自行判斷。注意
,這裏等號仍是要的
def myFunc(p1: Int) = { //something }
三、unit返回值的狀況下,直接省略返回值類型和等號
def myFunc(var p1 : Int) { //something // return unit }
四、函數只有一行的情形下省略返回值和大括號
def max2(x: Int, y: Int) = if (x > y) x else y def greet() = println("Hello, world!")
Scala 提供了多種不一樣的函數調用方式:
如下是調用方法的標準格式:
functionName( 參數列表 )
若是函數使用了實例的對象來調用,咱們可使用相似java的格式 (使用 . 號):
[instance.]functionName( 參數列表 )
Scala的解釋器在解析函數參數(function arguments)時有兩種方式:
在進入函數內部前,傳值調用方式就已經將參數表達式的值計算完畢,而傳名調用是在函數內部進行參數表達式的值計算的。
這就形成了一種現象,每次使用傳名調用時,解釋器都會計算一次表達式的值。
object Test {
def main(args: Array[String]) { delayed(time()); } def time() = { println("獲取時間,單位爲納秒") System.nanoTime } def delayed( t: => Long ) = { println("在 delayed 方法內") println("參數: " + t) t } }
以上實例中咱們聲明瞭 delayed 方法, 該方法在變量名和變量類型使用 =>
符號來設置傳名調用。執行以上代碼,輸出結果以下:
在 delayed 方法內 獲取時間,單位爲納秒 參數: 241550840475831 獲取時間,單位爲納秒
分析可得,delayed()中的time()參數先是沒有調用,在打印t時再計算調用的.
咱們把t: => Long
改爲t: Long
,打印結果就變爲:
獲取時間,單位爲納秒 在 delayed 方法內 參數: 241550840475831
可能如今你們有些亂,若是把這裏的t: => Long
改爲t: () => Long
我想你們就清楚了,方便記憶,能夠認爲這裏的t
並非一個值類型參數,而是一個函數類型的參數.
只是調用的時候,使用=
指定參數而已,好比:
object Test {
def main(args: Array[String]) { printInt(b=5, a=7); } def printInt( a:Int, b:Int ) = { println("Value of a : " + a ); println("Value of b : " + b ); } }
Scala 容許你指明函數的最後一個參數能夠是重複的,即咱們不須要指定函數參數的個數,能夠向函數傳入可變長度參數列表。
Scala 經過在參數的類型以後放一個星號來設置可變參數(可重複的參數)。例如:
object Test {
def main(args: Array[String]) { printStrings("Runoob", "Scala", "Python"); } def printStrings( args:String* ) = { var i : Int = 0; for( arg <- args ){ println("Arg value[" + i + "] = " + arg ); i = i + 1; } } }
遞歸函數意味着函數能夠調用它自己。經常使用的好比計算階乘.
在定義函數的時候使用=
設置默認值,如:
def addInt( a:Int=5, b:Int=7 ) : Int = { }
Scala 中容許使用高階函數,高階函數可使用其餘函數做爲參數,或者使用函數做爲輸出結果。
我麼能夠在 Scala 函數內定義函數,定義在函數內的函數稱之爲局部函數。
Scala 中定義匿名函數的語法很簡單,箭頭左邊是參數列表,右邊是函數體。
使用匿名函數後,咱們的代碼變得更簡潔了。
var mul = (x: Int, y: Int) => x*y
Scala 偏應用函數是一種表達式,你不須要提供函數須要的全部參數,只須要提供部分,或不提供所需參數。
以下實例,咱們打印日誌信息:
import java.util.Date object Test { def main(args: Array[String]) { val date = new Date log(date, "message1" ) Thread.sleep(1000) log(date, "message2" ) Thread.sleep(1000) log(date, "message3" ) } def log(date: Date, message: String) = { println(date + "----" + message) } }
輸出結果爲:
Mon Dec 02 12:52:41 CST 2013----message1 Mon Dec 02 12:52:41 CST 2013----message2 Mon Dec 02 12:52:41 CST 2013----message3
咱們可使用偏應用函數優化以上方法,綁定第一個 date 參數,第二個參數使用下劃線(_)替換缺失的參數列表,並把這個新的函數賦給變量。
以下:
import java.util.Date object Test { def main(args: Array[String]) { val date = new Date val logWithDateBound = log(date, _ : String) logWithDateBound("message1" ) Thread.sleep(1000) logWithDateBound("message2" ) Thread.sleep(1000) logWithDateBound("message3" ) } def log(date: Date, message: String) = { println(date + "----" + message) } }
柯里化(Currying)指的是將原來接受兩個參數的函數變成新的接受兩次一個參數的函數的過程。
以下,首先咱們定義一個函數:
def add(x:Int,y:Int)=x+y
那麼咱們應用的時候,應該是這樣用:add(1,2)
調用方法.
如今咱們把這個函數變一下形:
def add(x:Int)(y:Int) = x + y
咱們使用add(1)(2)
,最後結果都同樣是3,這種方式(過程)就叫柯里化。
閉包是一個函數實現方式,返回值依賴於聲明在函數外部的一個或多個變量。
完整實例:
object Test {
def main(args: Array[String]) {
println( "muliplier(1) value = " + multiplier(1) ) println( "muliplier(2) value = " + multiplier(2) ) } var factor = 3 val multiplier = (i:Int) => i * factor }
是其實和js的閉包同樣.
實例:
object Test {
val greeting: String = "Hello,World!" def main(args: Array[String]) { println( greeting ) } }
以上實例定義了變量 greeting,爲字符串常量,它的類型爲 String (java.lang.String)。
在 Scala 中,字符串的類型其實是 Java String,Scala自己沒有 String 類。
在 Scala 中,String 是一個不可變的對象
,因此該對象不可被修改。這就意味着你若是修改字符串就會產生一個新的字符串對象。
建立字符串實例以下:
var greeting = "Hello World!"; 或 var greeting:String = "Hello World!";
String 類中使用 concat() 方法來鏈接兩個字符串:string1.concat(string2)
一樣你也可使用加號(+)來鏈接.string1 + string2
object Test { def main(args: Array[String]) { val buf = new StringBuilder; buf += 'a' //+= 對字符 buf ++= "bcdef" //++= 對字符串 println( "buf is : " + buf.toString ); } }
StringBuffer 相似,就不說了.
StringBuilder和StringBuffer區別是歷代面試重點考點,主要區別以下.
StringBuilder | StringBuffer |
---|---|
非線程安全的 | 線程安全的 |
效率高 | 效率低 |
上面只是基礎問題,但實際使用中,不多用到StringBuffer,同時JVM對於(+)拼接也作了優化,在非循環狀況下自動轉爲StringBuilder.本段引自
printf()
方法來格式化字符串並輸出;format()
方法能夠返回 String 對象而不是 PrintStream 對象。object Test { def main(args: Array[String]) { var floatVar = 12.456 var intVar = 2000 var stringVar = "菜鳥教程!" var fs = printf("浮點型變量爲 " + "%f, 整型變量爲 %d, 字符串爲 " + " %s", floatVar, intVar, stringVar) println(fs) } }
和java基本一致!
Scala 語言中提供的數組是用來存儲固定大小
的同類型
元素,數組對於每一門編程語言來講都是重要的數據結構之一。
如下是 Scala 數組聲明的語法格式:
var z:Array[String] = new Array[String](3)
或
var z = new Array[String](3)
而後就能夠經過索引來訪問每一個元素:
z(0) = "Runoob" z(1) = "Baidu" z(4/2) = "Google"
咱們也可使用如下方式來定義一個數組:即定義時直接賦值...
var z = Array("Runoob", "Baidu", "Google")
數組的元素類型和數組的大小都是肯定的,因此當處理數組元素時候,咱們一般使用基本的 for 循環。
object Test {
def main(args: Array[String]) { var myList = Array(1.9, 2.9, 3.4, 3.5) // 輸出全部數組元素 for ( x <- myList ) { println( x ) } // 計算數組全部元素的總和 var total = 0.0; for ( i <- 0 to (myList.length - 1)) { total += myList(i); } println("總和爲 " + total); // 查找數組中的最大元素 var max = myList(0); for ( i <- 1 to (myList.length - 1) ) { if (myList(i) > max) max = myList(i); } println("最大值爲 " + max); } }
很少介紹
如下實例中,咱們使用 concat()
方法來合併兩個數組,concat() 方法中接受多個數組參數:
import Array._ object Test { def main(args: Array[String]) { var myList1 = Array(1.9, 2.9, 3.4, 3.5) var myList2 = Array(8.9, 7.9, 0.4, 1.5) var myList3 = concat(myList1, myList2) // 輸出全部數組元素 for ( x <- myList3 ) { println( x ) } } }
如下實例中,咱們使用了 range()
方法來生成一個區間範圍內的數組。range() 方法最後一個參數爲步長,默認爲 1:
import Array._ object Test { def main(args: Array[String]) { var myList1 = Array.range(10, 20, 2) var myList2 = Array.range(10,20) // 輸出全部數組元素 for ( x <- myList1 ) { print( " " + x ) } println() for ( x <- myList2 ) { print( " " + x ) } } }
執行以上代碼,輸出結果爲:
10 12 14 16 18 10 11 12 13 14 15 16 17 18 19
Scala 集合分爲可變的和不可變的集合。
可變集合能夠在適當的地方被更新或擴展。這意味着你能夠修改,添加,移除一個集合的元素。
而不可變集合類,相比之下,永遠不會改變。不過,你仍然能夠模擬添加,移除或更新操做。可是這些操做將在每一種狀況下都返回一個新的集合,同時使原來的集合不發生改變。
集合 | 描述 |
---|---|
List(列表) | 其元素以線性方式存儲,集合中能夠存放重複對象。 |
Set(集合) | 最簡單的一種集合。集合中的對象不按特定的方式排序,而且沒有重複對象。 |
Map(映射) | 把鍵對象和值對象映射的集合,它的每個元素都包含一對鍵對象和值對象。 |
元組 | 元組是不一樣類型的值的集合 |
Option | Option[T] 表示有可能包含值的容器,也可能不包含值。 |
Iterator(迭代器) | 迭代器不是一個容器,更確切的說是逐一訪問容器內元素的方法。 |
下面是各個集合的簡單實現:
// 定義整型 List
val x = List(1,2,3,4)
// 定義 Set var x = Set(1,3,5,7) // 定義 Map val x = Map("one" -> 1, "two" -> 2, "three" -> 3) // 建立兩個不一樣類型元素的元組 val x = (10, "Runoob") // 定義 Option val x:Option[Int] = Some(5)
迭代器 it 的兩個基本操做是 next 和 hasNext。
讓迭代器 it 逐個返回全部元素最簡單的方法是使用 while 循環:
object Test {
def main(args: Array[String]) { val it = Iterator("Baidu", "Google", "Runoob", "Taobao") while (it.hasNext){ println(it.next()) } } }
類是對象的抽象,而對象是類的具體實例。類是抽象的,不佔用內存,而對象是具體的,佔用存儲空間。類是用於建立對象的藍圖,它是一個定義包括在特定類型的對象中的方法和變量的軟件模板。
實例以下:
object StudyClass {
def main(args: Array[String]) { val pt = new Point(10, 20); // 移到一個新的位置 pt.move(10, 10); } } 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); } }
Scala繼承一個基類跟Java很類似, 但咱們須要注意一下幾點:
實例演示:
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); } } 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 的座標點 : " + x); println ("y 的座標點 : " + y); println ("z 的座標點 : " + z); } }
在 Scala 中,是沒有 static 這個東西的,可是它也爲咱們提供了單例模式的實現方法,那就是使用關鍵字 object。
Scala 中使用單例模式時,除了定義的類以外,還要定義一個同名的 object 對象,它和類的區別是,object對象不能帶參數。
當單例對象與某個類共享同一個名稱時,他被稱做是這個類的伴生對象:companion object。你必須在同一個源文件裏定義類和它的伴生對象。類被稱爲是這個單例對象的伴生類:companion class。
類和它的伴生對象能夠互相訪問其私有成員。
class singleObject(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 singleObject(10, 20) printPoint() def printPoint(){ println ("x 的座標點 : " + point.x); println ("y 的座標點 : " + point.y); } } }
// 私有構造方法 class CompanionObject private(val color:String) { println("建立" + this) override def toString(): String = "顏色標記:"+ color } // 伴生對象,與類共享名字,能夠訪問類的私有屬性和方法 object CompanionObject{ private val markers: Map[String, CompanionObject] = Map( "red" -> new CompanionObject("red"), "blue" -> new CompanionObject("blue"), "green" -> new CompanionObject("green") ) def apply(color:String) = { if(markers.contains(color)) Some(markers(color)) else None } def getCompanionObject(color:String) = { if(markers.contains(color)) Some(markers(color)) else None } def main(args: Array[String]) { println(CompanionObject("red")) // 單例函數調用,省略了.(點)符號 println(CompanionObject getCompanionObject "blue") // println(CompanionObject.getCompanionObject("blue")) } }
Scala Trait(特徵) 至關於 Java 的接口,實際上它比接口還功能強大。
與接口不一樣的是,它還能夠定義屬性和方法的實現。
通常狀況下Scala的類只可以繼承單一父類,可是若是是 Trait(特徵) 的話就能夠繼承多個,從結果來看就是實現了多重繼承。
簡單實例:
trait Equal {
def isEqual(x: Any): Boolean def isNotEqual(x: Any): Boolean = !isEqual(x) }
以上Trait(特徵)由兩個方法組成:isEqual 和 isNotEqual。isEqual 方法沒有定義方法的實現,isNotEqual定義了方法的實現。子類繼承特徵能夠實現未被實現的方法。因此其實 Scala Trait(特徵)更像 Java 的抽象類。
如下展現Trait的完整實例:
trait StudyTrait {
def isEqual(x: Any): Boolean def isNotEqual(x: Any): Boolean = !isEqual(x) } class Point(xc: Int, yc: Int) extends StudyTrait { var x: Int = xc var y: Int = yc def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == x } object Test2 { def main(args: Array[String]) { val p1 = new Point(2, 3) val p2 = new Point(2, 3) val p3 = new Point(3, 3) println(p1.isNotEqual(p2)) println(p1.isNotEqual(p3)) println(p1.isNotEqual(2)) } }
特徵也能夠有構造器,由字段的初始化和其餘特徵體中的語句構成。
構造器的執行順序:
++構造器的順序是類的線性化的反向。線性化是描述某個類型的全部超類型的一種技術規格。++
上面那句話說人話就是,最右邊的特質最早實例化,當其中有
super
字樣調用方法時,調用的是它左側的類方法,若是左側與它不是同一組,則真正調用父類方法.也就是super
是動態調用的.
模式匹配是FP語言的一大利器,務必學好,本篇僅是入門.
一個模式匹配包含了一系列備選項,每一個都開始於關鍵字 case。每一個備選項都包含了一個模式及一到多個表達式。箭頭符號 => 隔開了模式和表達式。
如下是一個簡單的整型值模式匹配實例:
object Test {
def main(args: Array[String]) { println(matchTest(3)) } def matchTest(x: Int): String = x match { case 1 => "one" case 2 => "two" case _ => "many" } }
match 對應 Java 裏的 switch,可是寫在選擇器表達式以後。即:選擇器 match {備選項}。
咱們還能夠匹配不一樣類型,像這樣:
object Test {
def main(args: Array[String]) { println(matchTest("two")) println(matchTest("test")) println(matchTest(1)) println(matchTest(6)) } def matchTest(x: Any): Any = x match { case 1 => "one" case "two" => 2 case y: Int => "scala.Int" case _ => "many" } }
使用了case關鍵字的類定義就是就是樣例類(case classes),樣例類是種特殊的類,通過優化以用於模式匹配。
如下是樣例類的簡單實例:
object Test { def main(args: Array[String]) { val alice = new Person("Alice", 25) val bob = new Person("Bob", 32) val charlie = new Person("Charlie", 32) for (person <- List(alice, bob, charlie)) { person match { case Person("Alice", 25) => println("Hi Alice!") case Person("Bob", 32) => println("Hi Bob!") case Person(name, age) => println("Age: " + age + " year, name: " + name + "?") } } } // 樣例類 case class Person(name: String, age: Int) }
在聲明樣例類時,下面的過程自動發生了:
private[this] val
,除非顯式被聲明爲var
,可是並不推薦這麼作;Scala 經過 scala.util.matching 包中的 Regex 類來支持正則表達式。
如下實例演示了使用正則表達式查找單詞 Scala
:
import scala.util.matching.Regex object StudyRegex { def main(args: Array[String]) { val pattern = "Scala".r() val str = "Scala is Scalable and cool" println(pattern.findFirstIn(str)) } }
執行以上代碼,輸出結果爲:
Some(Scala)
實例中使用 String 類的 r() 方法構造了一個Regex對象。
而後使用 findFirstIn 方法找到首個匹配項。
若是須要查看全部的匹配項可使用 findAllIn 方法。
你可使用 mkString( ) 方法來鏈接正則表達式匹配結果的字符串,並可使用管道(|)來設置不一樣的模式:
import scala.util.matching.Regex object Test { def main(args: Array[String]) { val pattern = new Regex("(S|s)cala") // 首字母能夠是大寫 S 或小寫 s val str = "Scala is scalable and cool" println((pattern findAllIn str).mkString(",")) // 使用逗號 , 鏈接返回結果 } }
執行以上代碼,輸出結果爲:
Scala,scala
若是你須要將匹配的文本替換爲指定的關鍵詞,可使用 replaceFirstIn( ) 方法來替換第一個匹配項,使用 replaceAllIn( ) 方法替換全部匹配項,實例以下:
object Test { def main(args: Array[String]) { val pattern = "(S|s)cala".r val str = "Scala is scalable and cool" println(pattern replaceFirstIn(str, "Java")) } }
執行以上代碼,輸出結果爲:
Java is scalable and cool
Scala 拋出異常的方法和 Java同樣,使用 throw
方法,例如,拋出一個新的參數異常:
throw new IllegalArgumentException
異常捕捉的機制與其餘語言中同樣,若是有異常發生,catch字句是按次序捕捉的。
所以,在catch字句中,越具體的異常越要靠前,越廣泛的異常越靠後。 若是拋出的異常不在catch字句中,該異常則沒法處理,會被升級到調用者處。
捕捉異常的catch子句,語法與其餘語言中不太同樣。在Scala裏,借用了模式匹配的思想來作異常的匹配,所以,在catch的代碼裏,是一系列case字句,以下例所示:
import java.io.FileReader import java.io.FileNotFoundException import java.io.IOException object Test { def main(args: Array[String]) { try { val f = new FileReader("input.txt") } catch { case ex: FileNotFoundException =>{ println("Missing file exception") } case ex: IOException => { println("IO Exception") } } finally { println("Exiting finally...") } } }
執行以上代碼,輸出結果爲:
Missing file exception Exiting finally...
提取器是從傳遞給它的對象中提取出構造該對象的參數。
Scala 提取器是一個帶有unapply方法的對象。unapply方法算是apply方法的反向操做:unapply接受一個對象,而後從對象中提取值,提取的值一般是用來構造該對象的值。
如下實例演示了郵件地址的提取器對象:
object Test {
def main(args: Array[String]) { println ("Apply 方法 : " + apply("Zara", "gmail.com")); println ("Unapply 方法 : " + unapply("Zara@gmail.com")); println ("Unapply 方法 : " + unapply("Zara Ali")); } // 注入方法 (可選) def apply(user: String, domain: String) = { user +"@"+ domain } // 提取方法(必選) def unapply(str: String): Option[(String, String)] = { val parts = str split "@" if (parts.length == 2){ Some(parts(0), parts(1)) }else{ None } } }
執行以上代碼,輸出結果爲:
Apply 方法 : Zara@gmail.com Unapply 方法 : Some((Zara,gmail.com)) Unapply 方法 : None
以上對象定義了兩個方法: apply 和 unapply 方法。經過 apply 方法咱們無需使用 new 操做就能夠建立對象。因此你能夠經過語句 Test("Zara", "gmail.com") 來構造一個字符串 "Zara@gmail.com"。
unapply方法算是apply方法的反向操做:unapply接受一個對象,而後從對象中提取值,提取的值一般是用來構造該對象的值。實例中咱們使用 Unapply 方法從對象中提取用戶名和郵件地址的後綴。
在咱們實例化一個類的時,能夠帶上0個或者多個的參數,編譯器在實例化的時會調用 apply 方法。咱們能夠在類和對象中都定義 apply 方法。
就像咱們以前提到過的,unapply 用於提取咱們指定查找的值,它與 apply 的操做相反。 當咱們在提取器對象中使用 match 語句時,unapply 將自動執行,以下所示:
object Test { def main(args: Array[String]) { val x = Test(5) println(x) x match { case Test(num) => println(x + " 是 " + num + " 的兩倍!") //unapply 被調用 case _ => println("沒法計算") } } def apply(x: Int) = x*2 def unapply(z: Int): Option[Int] = if (z%2==0) Some(z/2) else None }
執行以上代碼,輸出結果爲:
10 10 是 5 的兩倍!
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("BarryW") writer.close() } }
執行以上代碼,會在你的當前目錄下生產一個 test.txt 文件,文件內容爲"菜鳥教程".
有時候咱們須要接收用戶在屏幕輸入的指令來處理程序。實例以下:
object Test {
def main(args: Array[String]) { print("請輸入: " ) val line = Console.readLine println("謝謝,你輸入的是: " + line) } }
從文件讀取內容很是簡單。咱們可使用 Scala 的 Source 類及伴生對象來讀取文件。
如下實例演示了從 "test.txt"(以前已建立過) 文件中讀取內容:
import scala.io.Source
object Test { def main(args: Array[String]) { println("文件內容爲:" ) Source.fromFile("test.txt" ).foreach{ print } } }
以上都是Scala中最簡單基礎的入門,以及一些在Java等面向對象程序中比較經常使用的功能, 我接下來的文章中,會繼續介紹Scala的一些高級
功能和彆扭
的語法糖, Scala就是經過那些彆扭
的語法大大縮減了代碼量, 而且使程序更加易寫易讀. 但願本文可讓你們感覺到FP簡潔不簡單
的魅力.