“大道泛兮,其可左右。
萬(wàn)物恃之而生而不辭,功成不名有。
衣養(yǎng)萬(wàn)物而不為主,常無(wú)欲,可名于小;萬(wàn)物歸焉而不為主,可名為大。
是以圣人之能成大也,以其不為大也,故能成大?!?sup>[1]
本文的出發(fā)點(diǎn)是記錄scala與傳統(tǒng)java以及python的不同之處。
行結(jié)尾方式 抑或 換行符
跟java不同的地方在于,每一行不必以“;”結(jié)尾,除了一個(gè)行如果寫(xiě)多條語(yǔ)句時(shí),前面的語(yǔ)句必須以“;”結(jié)尾。
val rdd = sc.parallelize([1,2,3,4]);println(rdd)
注釋
完全跟java一樣,/**/用于多行;//用于單行。
package
引入包,有兩種方式:
- 跟java相同
package com.c-goshine.sh.demo;
- 有些類(lèi)似c#
package com.cgoshine.sh.demo{
}
使用這種方式可以在一個(gè)文件中定義多個(gè)包。
import
跟python有些像,import可以寫(xiě)在文件的任何地方。
導(dǎo)入某個(gè)包下的所有成員,這個(gè)跟java的方式有些不同,用“_”來(lái)代替java的“*”,如:
import com.cgoshine.sh.demo._ //引入包內(nèi)所有成員
如果想引用包里的幾個(gè)成員,可以使用選擇器selector
import java.awt.{Color, Font}
// 重命名成員
import java.util.{HashMap => JavaHashMap}
// 隱藏成員
import java.util.{HashMap => _, _} // 引入了util包的所有成員,但是HashMap被隱藏了
注意:默認(rèn)情況下,Scala 總會(huì)引入 java.lang._ 、 scala._ 和 Predef._,這里也能解釋?zhuān)瑸槭裁匆詓cala開(kāi)頭的包,在使用時(shí)都是省去scala.的。
數(shù)據(jù)類(lèi)型
scala與java有著相同的數(shù)據(jù)類(lèi)型。
| 數(shù)據(jù)類(lèi)型 | 描述 |
|---|---|
| Byte | 8位有符號(hào)補(bǔ)碼整數(shù)。數(shù)值區(qū)間為 -128 到 127 |
| Short | 16位有符號(hào)補(bǔ)碼整數(shù)。數(shù)值區(qū)間為 -32768 到 32767 |
| Int | 32位有符號(hào)補(bǔ)碼整數(shù)。數(shù)值區(qū)間為 -2147483648 到 2147483647 |
| Long | 64位有符號(hào)補(bǔ)碼整數(shù)。數(shù)值區(qū)間為 -9223372036854775808 到 9223372036854775807 |
| Float | 32位IEEE754單精度浮點(diǎn)數(shù) |
| Double | 64位IEEE754單精度浮點(diǎn)數(shù) |
| Char | 16位無(wú)符號(hào)Unicode字符, 區(qū)間值為 U+0000 到 U+FFFF |
| String | 字符序列 |
| Boolean | true或false |
| Unit | 表示無(wú)值,和其他語(yǔ)言中void等同。用作不返回任何結(jié)果的方法的結(jié)果類(lèi)型。Unit只有一個(gè)實(shí)例值,寫(xiě)成()。 |
| Null | null 或空引用 |
| Nothing | Nothing類(lèi)型在Scala的類(lèi)層級(jí)的最低端;它是任何其他類(lèi)型的子類(lèi)型。 |
| Any | Any是所有其他類(lèi)的超類(lèi) |
| AnyRef | AnyRef類(lèi)是Scala里所有引用類(lèi)(reference class)的基類(lèi) |
變量聲明
用var聲明變量;用val聲明常量
格式:var VariableName : DataType [= Initial Value]
var ss:String [="rzaor"]
var ss //裸奔方式
訪問(wèn)修飾符
public private protected
- private
默認(rèn)public,其中private比java要嚴(yán)格(在嵌套類(lèi)情況下,外層類(lèi)甚至不能訪問(wèn)被嵌套類(lèi)的私有成員)。
class Outer{
class Inner{
private def f(){println("f")}
class InnerMost{
f() // 正確
}
}
(new Inner).f() //錯(cuò)誤
}
- protected
同樣也比java的要嚴(yán)格。因?yàn)樗辉试S保護(hù)成員在定義了該成員的的類(lèi)的子類(lèi)中被訪問(wèn)。而在java中,用protected關(guān)鍵字修飾的成員,除了定義了該成員的類(lèi)的子類(lèi)可以訪問(wèn),同一個(gè)包里的其他類(lèi)也可以進(jìn)行訪問(wèn)。
package p{
class Super{
protected def f() {println("f")}
}
class Sub extends Super{
f()
}
class Other{
(new Super).f() //錯(cuò)誤
}
}
- 作用域保護(hù)
private[x]
protected[x]
理解為:如果寫(xiě)成private[x],讀作"這個(gè)成員除了對(duì)[…]中的類(lèi)或[…]中的包中的類(lèi)及它們的伴生對(duì)像可見(jiàn)外,對(duì)其它所有類(lèi)都是private。這種技巧在橫跨了若干包的大型項(xiàng)目中非常有用,它允許你定義一些在你項(xiàng)目的若干子包中可見(jiàn)但對(duì)于項(xiàng)目外部的客戶(hù)卻始終不可見(jiàn)的東西。
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
}
}
}
類(lèi)Navigator被標(biāo)記為private[bobsrockets]就是說(shuō)這個(gè)類(lèi)對(duì)包含在bobsrockets包里的所有的類(lèi)和對(duì)象可見(jiàn)。
比如說(shuō),從Vehicle對(duì)象里對(duì)Navigator的訪問(wèn)是被允許的,因?yàn)閷?duì)象Vehicle包含在包launch中,而launch包在bobsrockets中,相反,所有在包bobsrockets之外的代碼都不能訪問(wèn)類(lèi)Navigator。
位運(yùn)算符
位運(yùn)算符用來(lái)對(duì)二進(jìn)制位進(jìn)行操作,~,&,|,^分別為取反,按位與與,按位與或,按位與異或運(yùn)算。
如果指定 A = 60; 及 B = 13; 兩個(gè)變量對(duì)應(yīng)的二進(jìn)制為:
A = 0011 1100
B = 0000 1101
-------位運(yùn)算----------
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011
Scala 中的按位運(yùn)算法則如下:
| 運(yùn)算符 | 描述 | 實(shí)例 |
|---|---|---|
| & | 按位與運(yùn)算符 | (a & b) 輸出結(jié)果 12 ,二進(jìn)制解釋?zhuān)?0000 1100 |
| | | 按位或運(yùn)算符 | (a | b) 輸出結(jié)果 61 ,二進(jìn)制解釋?zhuān)?0011 1101 |
| ^ | 按位異或運(yùn)算符 | (a ^ b) 輸出結(jié)果 49 ,二進(jìn)制解釋?zhuān)?0011 0001 |
| ~ | 按位取反運(yùn)算符 | (~a ) 輸出結(jié)果 -61 ,二進(jìn)制解釋?zhuān)?1100 0011, 在一個(gè)有符號(hào)二進(jìn)制數(shù)的補(bǔ)碼形式。 |
| << | 左移動(dòng)運(yùn)算符 | a << 2 輸出結(jié)果 240 ,二進(jìn)制解釋?zhuān)?1111 0000 |
| >> | 右移動(dòng)運(yùn)算符 | a >> 2 輸出結(jié)果 15 ,二進(jìn)制解釋?zhuān)?0000 1111 |
| >>> | 無(wú)符號(hào)右移 | A >>>2 輸出結(jié)果 15, 二進(jìn)制解釋: 0000 1111 |
函數(shù) 方法
Scala 有函數(shù)和方法,二者在語(yǔ)義上的區(qū)別很小。Scala 方法是類(lèi)的一部分,而函數(shù)是一個(gè)對(duì)象可以賦值給一個(gè)變量。換句話(huà)來(lái)說(shuō)在類(lèi)中定義的函數(shù)即是方法。
- 函數(shù)聲明
def functionName ([參數(shù)列表]) : [return type]
- 函數(shù)定義
def functionName ([參數(shù)列表]) : [return type] = {
function body
return [expr]
}
如果函數(shù)沒(méi)有返回值,可以返回為 Unit,這個(gè)類(lèi)似于 Java 的 void。
object add{
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
def printMe( ) : Unit = {
println("Hello, Scala!")
}
}
閉包
閉包是一個(gè)函數(shù),返回值依賴(lài)于聲明在函數(shù)外部的一個(gè)或多個(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ù),而是自由變量,考慮下面代碼:
var factor = 3
val multiplier = (i:Int) => i * factor
這樣定義的函數(shù)變量 multiplier 成為一個(gè)"閉包",因?yàn)樗玫胶瘮?shù)外面定義的變量,定義這個(gè)函數(shù)的過(guò)程是將這個(gè)自由變量捕獲而構(gòu)成一個(gè)封閉的函數(shù)。
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
}
函數(shù)的閉包就是當(dāng)函數(shù)的參數(shù)超出其作用域時(shí),我們還能對(duì)參數(shù)進(jìn)行訪問(wèn)。
scala> def iscala(content:String) = (message:String) => println(content + " "+ message)
iscala: (content: String)String => Unit
scala> val func1 = iscala("spark")
func1: String => Unit = $$Lambda$1228/248295195@3dceec83
scala> func1("hadoop")
spark hadoop
scala> func1("hbase")
spark hbase
在調(diào)用func1時(shí),將之前的content參數(shù)的值延續(xù)了下來(lái)。
字符串連接
string1.concat(string2);
同樣你也可以使用加號(hào)(+)來(lái)連接
- 創(chuàng)建格式化字符串
object Test {
def main(args: Array[String]) {
var floatVar = 12.456
var intVar = 2000
var stringVar = "scala multi-paradigm!"
var fs = printf("浮點(diǎn)型變量為 " +
"%f, 整型變量為 %d, 字符串為 " +
" %s", floatVar, intVar, stringVar)
println(fs)
}
}
for循環(huán)
for( var x <- Range ){
statement(s);
}
Range 可以是一個(gè)數(shù)字區(qū)間表示 i to j ,或者 i until j。左箭頭 <- 用于為變量 x 賦值。
舉個(gè)例子:
object Test {
def main(args: Array[String]) {
var a = 0;
// for 循環(huán)
for( a <- 1 to 10){
println( "Value of a: " + a );
}
}
}
類(lèi)和對(duì)象
Scala中的類(lèi)不聲明為public,一個(gè)Scala源文件中可以有多個(gè)類(lèi)。
class Point(xc: Int, yc: Int) {
……
}
繼承
Scala繼承一個(gè)基類(lèi)跟Java很相似, 但我們需要注意以下幾點(diǎn):
- 重寫(xiě)一個(gè)非抽象方法必須使用override修飾符。
- 只有主構(gòu)造函數(shù)才可以往基類(lèi)的構(gòu)造函數(shù)里寫(xiě)參數(shù)。
- 在子類(lèi)中重寫(xiě)超類(lèi)的抽象方法時(shí),你不需要使用override關(guān)鍵字。
繼承會(huì)繼承父類(lèi)的所有屬性和方法,Scala 只允許繼承一個(gè)父類(lèi)。
單例對(duì)象 & 伴生對(duì)象
Scala單例對(duì)象是十分重要的,不像Java一樣,有靜態(tài)類(lèi)、靜態(tài)成員、靜態(tài)方法,但是Scala提供了object對(duì)象,這個(gè)object對(duì)象類(lèi)似于Java的靜態(tài)類(lèi),它的成員、它的方法都默認(rèn)是靜態(tài)的。
如果object的靜態(tài)成員要被外界訪問(wèn),則該成員不能被private修飾。
伴生對(duì)象首先是一個(gè)單例對(duì)象,單例對(duì)象用關(guān)鍵字object定義。在Scala中,單例對(duì)象分為兩種,一種是并未自動(dòng)關(guān)聯(lián)到特定類(lèi)上的單例對(duì)象,稱(chēng)為獨(dú)立對(duì)象 (Standalone Object);另一種是關(guān)聯(lián)到一個(gè)類(lèi)上的單例對(duì)象,該單例對(duì)象與該類(lèi)共有相同名字,則這種單例對(duì)象稱(chēng)為伴生對(duì)象(Companion Object),對(duì)應(yīng)類(lèi)稱(chēng)為伴生類(lèi)。
Trait(特性)
Scala Trait(特征) 相當(dāng)于 Java 的接口,實(shí)際上它比接口還功能強(qiáng)大。
與接口不同的是,它還可以定義屬性和方法的實(shí)現(xiàn)。
一般情況下Scala的類(lèi)只能夠繼承單一父類(lèi),但是如果是 Trait(特征) 的話(huà)就可以繼承多個(gè),從結(jié)果來(lái)看就是實(shí)現(xiàn)了多重繼承。
Trait(特征) 定義的方式與類(lèi)類(lèi)似,但它使用的關(guān)鍵字是 trait。
package com.cgoshine.sh.demo.scala
trait Equal {
def isEqual(x:Any):Boolean
def isNotEqual(x:Any):Boolean = !isEqual(x)
}
isEqual 方法沒(méi)有定義方法的實(shí)現(xiàn),isNotEqual定義了方法的實(shí)現(xiàn)。子類(lèi)繼承特征可以實(shí)現(xiàn)未被實(shí)現(xiàn)的方法。所以其實(shí) Scala Trait(特征)更像 Java 的抽象類(lèi)。
implements這個(gè)在scala中到目前為止還沒(méi)見(jiàn)到,即使“實(shí)現(xiàn)”Trait中也是用的extends。
class Point(xc: Int, yc: Int) extends Equal {
……
}
模式匹配
Scala 提供了強(qiáng)大的模式匹配機(jī)制,應(yīng)用也非常廣泛。
match 對(duì)應(yīng) Java 里的 switch,但是寫(xiě)在選擇器表達(dá)式之后。即: 選擇器 match {備選項(xiàng)}。
一個(gè)模式匹配包含了一系列備選項(xiàng),每個(gè)都開(kāi)始于關(guān)鍵字 case。每個(gè)備選項(xiàng)都包含了一個(gè)模式及一到多個(gè)表達(dá)式。箭頭符號(hào) => 隔開(kāi)了模式和表達(dá)式。
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"
}
}
“_”,默認(rèn)的全匹配備選項(xiàng),即沒(méi)有找到其他匹配時(shí)的匹配項(xiàng),類(lèi)似 switch 中的 default。
- 使用樣例類(lèi)
使用了case關(guān)鍵字的類(lèi)定義就是就是樣例類(lèi)(case classes),樣例類(lèi)是種特殊的類(lèi),經(jīng)過(guò)優(yōu)化以用于模式匹配。
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 + "?")
}
}
}
// 樣例類(lèi)
case class Person(name: String, age: Int)
}
在聲明樣例類(lèi)時(shí),下面的過(guò)程自動(dòng)發(fā)生了:
構(gòu)造器的每個(gè)參數(shù)都成為val,除非顯式被聲明為var,但是并不推薦這么做;
在伴生對(duì)象中提供了apply方法,所以可以不使用new關(guān)鍵字就可構(gòu)建對(duì)象;
提供unapply方法使模式匹配可以工作;
生成toString、equals、hashCode和copy方法,除非顯示給出這些方法的定義。
正則表達(dá)式
Scala 通過(guò) scala.util.matching 包中的 Regex 類(lèi)來(lái)支持正則表達(dá)式。
import scala.util.matching.Regex
object Test {
def main(args: Array[String]) {
val pattern = "Scala".r
val str = "Scala is Scalable and cool"
println(pattern findFirstIn str)
}
}
使用 String 類(lèi)的 r() 方法構(gòu)造了一個(gè)Regex對(duì)象,然后使用 findFirstIn 方法找到首個(gè)匹配項(xiàng)。
如果需要查看所有的匹配項(xiàng)可以使用 findAllIn 方法。你可以使用 mkString( ) 方法來(lái)連接正則表達(dá)式匹配結(jié)果的字符串,并可以使用管道(|)來(lái)設(shè)置不同的模式:
import scala.util.matching.Regex
object Test {
def main(args: Array[String]) {
val pattern = new Regex("(S|s)cala") // 首字母可以是大寫(xiě) S 或小寫(xiě) s
val str = "Scala is scalable and cool"
println((pattern findAllIn str).mkString(",")) // 使用逗號(hào) , 連接返回結(jié)果
}
}
輸出結(jié)果為:
$ scalac Test.scala
$ scala Test
Scala,scala
如果你需要將匹配的文本替換為指定的關(guān)鍵詞,可以使用 replaceFirstIn( ) 方法來(lái)替換第一個(gè)匹配項(xiàng),使用 replaceAllIn( ) 方法替換所有匹配項(xiàng)。
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"))
}
}
Scala 的正則表達(dá)式繼承了 Java 的語(yǔ)法規(guī)則,Java 則大部分使用了 Perl 語(yǔ)言的規(guī)則。
- 規(guī)則:
| 表達(dá)式 | 匹配規(guī)則 |
|---|---|
| ^ | 匹配輸入字符串開(kāi)始的位置。 |
| $ | 匹配輸入字符串結(jié)尾的位置。 |
| . | 匹配除"\r\n"之外的任何單個(gè)字符。 |
| [...] | 字符集。匹配包含的任一字符。例如,"[abc]"匹配"plain"中的"a"。 |
| [^...] | 反向字符集。匹配未包含的任何字符。例如,"[^abc]"匹配"plain"中"p","l","i","n"。 |
| \A | 匹配輸入字符串開(kāi)始的位置(無(wú)多行支持) |
| \z | 字符串結(jié)尾(類(lèi)似$,但不受處理多行選項(xiàng)的影響) |
| \Z | 字符串結(jié)尾或行尾(不受處理多行選項(xiàng)的影響) |
| re* | 重復(fù)零次或更多次 |
| re+ | 重復(fù)一次或更多次 |
| re? | 重復(fù)零次或一次 |
| re{ n} | 重復(fù)n次 |
| re{ n,} | |
| re{ n, m} | 重復(fù)n到m次 |
| a|b | 匹配 a 或者 b |
| (re) | 匹配 re,并捕獲文本到自動(dòng)命名的組里 |
| (?: re) | 匹配 re,不捕獲匹配的文本,也不給此分組分配組號(hào) |
| (?> re) | 貪婪子表達(dá)式 |
| \w | 匹配字母或數(shù)字或下劃線或漢字 |
| \W | 匹配任意不是字母,數(shù)字,下劃線,漢字的字符 |
| \s | 匹配任意的空白符,相等于 [\t\n\r\f] |
| \S | 匹配任意不是空白符的字符 |
| \d | 匹配數(shù)字,類(lèi)似 [0-9] |
| \D | 匹配任意非數(shù)字的字符 |
| \G | 當(dāng)前搜索的開(kāi)頭 |
| \n | 換行符 |
| \b | 通常是單詞分界位置,但如果在字符類(lèi)里使用代表退格 |
| \B | 匹配不是單詞開(kāi)頭或結(jié)束的位置 |
| \t | 制表符 |
| \Q | 開(kāi)始引號(hào):\Q(a+b)3\E 可匹配文本 "(a+b)3"。 |
| \E | 結(jié)束引號(hào):\Q(a+b)3\E 可匹配文本 "(a+b)3"。 |
- 實(shí)例:
| 實(shí)例 | 描述 |
|---|---|
| . | 匹配除"\r\n"之外的任何單個(gè)字符。 |
| [Rr]uby | 匹配 "Ruby" 或 "ruby" |
| rub[ye] | 匹配 "ruby" 或 "rube" |
| [aeiou] | 匹配小寫(xiě)字母 :aeiou |
| [0-9] | 匹配任何數(shù)字,類(lèi)似 [0123456789] |
| [a-z] | 匹配任何 ASCII 小寫(xiě)字母 |
| [A-Z] | 匹配任何 ASCII 大寫(xiě)字母 |
| [a-zA-Z0-9] | 匹配數(shù)字,大小寫(xiě)字母 |
| [^aeiou] | 匹配除了 aeiou 其他字符 |
| [^0-9] | 匹配除了數(shù)字的其他字符 |
| \d | 匹配數(shù)字,類(lèi)似: [0-9] |
| \D | 匹配非數(shù)字,類(lèi)似: [^0-9] |
| \s | 匹配空格,類(lèi)似: [ \t\r\n\f] |
| \S | 匹配非空格,類(lèi)似: [^ \t\r\n\f] |
| \w | 匹配字母,數(shù)字,下劃線,類(lèi)似: [A-Za-z0-9_] |
| \W | 匹配非字母,數(shù)字,下劃線,類(lèi)似: [^A-Za-z0-9_] |
| ruby? | 匹配 "rub" 或 "ruby": y 是可選的 |
| ruby* | 匹配 "rub" 加上 0 個(gè)或多個(gè)的 y。 |
| ruby+ | 匹配 "rub" 加上 1 個(gè)或多個(gè)的 y。 |
| \d{3} | 剛好匹配 3 個(gè)數(shù)字。 |
| \d{3,} | 匹配 3 個(gè)或多個(gè)數(shù)字。 |
| \d{3,5} | 匹配 3 個(gè)、4 個(gè)或 5 個(gè)數(shù)字。 |
| \D\d+ | 無(wú)分組: + 重復(fù) \d |
| (\D\d)+/ | 分組: + 重復(fù) \D\d 對(duì) |
| ([Rr]uby(, )?)+ | 匹配 "Ruby"、"Ruby, ruby, ruby",等等 |
異常處理
Scala 的異常處理和其它語(yǔ)言比如 Java 類(lèi)似。
throw new FileNotFoundException
如果有異常發(fā)生,catch字句是按次序捕捉的。因此,在catch字句中,越具體的異常越要靠前,越普遍的異常越靠后。 如果拋出的異常不在catch字句中,該異常則無(wú)法處理,會(huì)被升級(jí)到調(diào)用者處。
捕捉異常的catch子句,語(yǔ)法與其他語(yǔ)言中不太一樣。在Scala里,借用了模式匹配的思想來(lái)做異常的匹配,因此,在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 語(yǔ)句
finally 語(yǔ)句用于執(zhí)行不管是正常處理還是有異常發(fā)生時(shí)都需要執(zhí)行的步驟。
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...")
}
}
}
提取器(Extractor)
提取器是從傳遞給它的對(duì)象中提取出構(gòu)造該對(duì)象的參數(shù)。
Scala 提取器是一個(gè)帶有unapply方法的對(duì)象。unapply方法算是apply方法的反向操作:unapply接受一個(gè)對(duì)象,然后從對(duì)象中提取值,提取的值通常是用來(lái)構(gòu)造該對(duì)象的值。
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
}
}
}
輸出:
$ scalac Test.scala
$ scala Test
Apply 方法 : Zara@gmail.com
Unapply 方法 : Some((Zara,gmail.com))
Unapply 方法 : None
Options Some None
Some和None都是Options的子類(lèi),Scala鼓勵(lì)你在變量和函數(shù)返回值可能不會(huì)引用任何值的時(shí)候使用Option類(lèi)型。在沒(méi)有值的時(shí)候,使用None;如果有值可以引用,就使用Some來(lái)包含這個(gè)值。
scala> val capitals = Map("France"->"Paris", "Japan"->"Tokyo", "China"->"Beijing")
capitals: scala.collection.immutable.Map[String,String] = Map(France -> Paris, Japan -> Tokyo, China -> Beijing)
scala> capitals get "France"
res0: Option[String] = Some(Paris)
scala> capitals get "Germany"
res1: Option[String] = None
當(dāng)程序回傳Some的時(shí)候,代表函式返回一個(gè)String,你可以調(diào)用get()函數(shù)獲得那個(gè)String,如果程序返回的是None,則代表沒(méi)有字符串可以給你。
在返回None,也就是沒(méi)有String給你的時(shí)候,如果你還硬要調(diào)用get()來(lái)取得 String 的話(huà),Scala一樣是會(huì)拋出一個(gè)NoSuchElementException異常給你的。
我們也可以選用另外一個(gè)方法,getOrElse。這個(gè)方法在這個(gè)Option是Some的實(shí)例時(shí)返回對(duì)應(yīng)的值,而在是None的實(shí)例時(shí)返回傳入的參數(shù)。換句話(huà)說(shuō),傳入getOrElse的參數(shù)實(shí)際上是默認(rèn)返回值。
scala> capitals get "Germany" get
warning: there was one feature warning; re-run with -feature for details
java.util.NoSuchElementException: None.get
……
scala> capitals get "France" get
warning: there was one feature warning; re-run with -feature for details
res3: String = Paris
scala> (capitals get "Germany") getOrElse "Oops"
res7: String = Oops
scala> capitals get "France" getOrElse "Oops"
res8: String = Paris
文件 I/O
Scala 進(jìn)行文件寫(xiě)操作,直接用的都是 java中 的 I/O 類(lèi) (java.io.File):
import java.io._
object Test {
def main(args: Array[String]) {
val writer = new PrintWriter(new File("demo.txt" ))
writer.write("com.cgoshine.sh.demo")
writer.close()
}
}
- 從屏幕讀取輸入
object Test {
def main(args: Array[String]) {
print("input your company's name : " )
val line = Console.readLine
println("thanks,your input is: " + line)
}
}
- 從文件讀取
從文件讀取內(nèi)容非常簡(jiǎn)單。我們可以使用 Scala 的 Source 類(lèi)及伴生對(duì)象來(lái)讀取文件。
import scala.io.Source
object Test {
def main(args: Array[String]) {
println("文件內(nèi)容為:" )
Source.fromFile("test.txt" ).foreach{
print
}
}
}
-
老子《道德經(jīng)》第三十四章,老子故里,中國(guó)鹿邑。 ?