5.1 關(guān)于Scala
5.1.1 與Java的密切關(guān)系
- Scala運(yùn)行在Java虛擬機(jī)上,這使得Scala可以和現(xiàn)存的應(yīng)用同時(shí)運(yùn)行。
- Scala可以直接使用Java類庫(kù),使得開發(fā)人員可以利用現(xiàn)有的框架和遺留代碼。
- Scala和Java一樣都是靜態(tài)類型語(yǔ)言,因此這兩種語(yǔ)言遵循一樣的編程哲學(xué)。
- Scala的語(yǔ)法與Java比較接近,使得開發(fā)人員可以快速掌握語(yǔ)言基礎(chǔ)。
- Scala既支持面向?qū)ο蠓盒鸵仓С趾瘮?shù)式編程泛型,這樣開發(fā)人員就可以逐步在代碼中運(yùn)用函數(shù)式編程的思想。
5.1.2與Java的不同之處
類型推斷
Scala類型推斷的極限在哪里?什么情況下必須要指定變量的類型?
函數(shù)式編程概念
可以通過不同方式使用已有的函數(shù)構(gòu)造出新函數(shù)。
不變量
變量是否可變必須一開始就明確,如果不知道變量是否可變,那么就應(yīng)該指定為不可變的。
在這種理念的指導(dǎo)下,Scala會(huì)要求你明確地決定一個(gè)變量是否可變。
高級(jí)程序構(gòu)造
5.1.4函數(shù)式語(yǔ)言特性
- 函數(shù)式程序由函數(shù)組成。
- 函數(shù)總是具有返回值。
- 函數(shù)對(duì)于相同的輸入總是會(huì)返回相同的值。
- 函數(shù)式程序禁止改變狀態(tài)或修改數(shù)據(jù)。一旦你設(shè)置了一個(gè)值,就無(wú)需再管它了。
Scala并不是一門純函數(shù)式編程語(yǔ)言。
5.2 第一天
5.2.1 Scala 類型
整數(shù)是對(duì)象。
scala> "abc" + 4
res6: String = abc4
scala> 4 + "abc"
res7: String = 4abc
scala> 4 + "1.0"
res8: String = 41.0
即使上面的代碼沒有報(bào)錯(cuò),也不能按照java的思路去理解,"abc" + 4
應(yīng)該理解為字符串有+(i:int)
這個(gè)方法,而4 + "abc"
應(yīng)該理解為int
有一個(gè)+(str : String)
方法。
本來以為在java中會(huì)報(bào)錯(cuò)的,結(jié)果沒有:
public class App
{
public static void main( String[] args )
{
System.out.println(4 + "abc");
System.out.println("abc" + 4);
System.out.println(4 + "1.0");
}
}
scala> 4 * "abc"
<console>:12: error: overloaded method value * with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int
cannot be applied to (String)
4 * "abc"
^
Scala是強(qiáng)類型的,使用類型推斷,并可以在編譯期間進(jìn)行類型檢查(不需要聲明變量的類型,并不代表變量是沒有類型的)。
scala> var i = 1
i: Int = 1
scala> i = "abc"
<console>:12: error: type mismatch;
found : String("abc")
required: Int
i = "abc"
^
Scala在編譯期間綁定變量類型。
i
就是int
類型,并且不可以改變。
5.2.2 表達(dá)式與條件
scala> 5 < 6
res10: Boolean = true
scala> 5 <= 6
res11: Boolean = true
scala> 5 <= 2
res12: Boolean = false
scala> 5 >= 2
res13: Boolean = true
scala> 5 != 2
res14: Boolean = true
if表達(dá)式
scala> val a = 1
a: Int = 1
scala> val b = 2
b: Int = 2
scala> if ( b < a) {
| println("true")
| } else {
| println("false")
| }
false
var
聲明不變量,var
聲明變量
空值、0不可轉(zhuǎn)換為布爾值
強(qiáng)類型是指這門語(yǔ)言檢查兩種類型是否兼容,如果不兼容則會(huì)拋出一個(gè)錯(cuò)誤或強(qiáng)制類型轉(zhuǎn)換。
靜態(tài)類型語(yǔ)言強(qiáng)迫在類型結(jié)構(gòu)的基礎(chǔ)上執(zhí)行多態(tài)。
scala> Nil
res16: scala.collection.immutable.Nil.type = List()
scala> if (0) { println("true")}
<console>:12: error: type mismatch;
found : Int(0)
required: Boolean
if (0) { println("true")}
^
scala> if (Nil) {println("true")}
<console>:12: error: type mismatch;
found : scala.collection.immutable.Nil.type
required: Boolean
if (Nil) {println("true")}
^
java中空值、0不可轉(zhuǎn)換為布爾值
Paste_Image.png
5.2.3 循環(huán)
object App {
def whileLooop {
var i = 1
while (i <= 3) {
println(i)
i += 1
}
}
def main(args: Array[String]) = {
whileLooop
}
}
在Scala中,public
是默認(rèn)的可見級(jí)別。
def forLoop {
var args = Array(1, 2, 4)
println("for loop using Java-style iteration")
for (i <- 0 until args.length) {
println(args(i))
}
}
def main(args: Array[String]) = {
forLoop
}
object App {
def rubyStyleForLoop(args: Array[String]) {
println("for loop using Ruby-style iteration")
args.foreach { arg =>
println(arg)
}
}
def main(args: Array[String]) = {
rubyStyleForLoop(Array("a", "b", "c"))
}
}
5.2.4范圍與元組
范圍
scala> val range = 0 until 10
range: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> range.start
res0: Int = 0
scala> range.end
res1: Int = 10
scala> range.step
res2: Int = 1
scala> (0 to 10) by 5
res3: scala.collection.immutable.Range = Range(0, 5, 10)
scala> (0 to 10) by 6
res4: scala.collection.immutable.Range = Range(0, 6)
scala> (0 to 10 by 6)
res5: scala.collection.immutable.Range = Range(0, 6)
scala> (0 until 10 by 5)
res6: scala.collection.immutable.Range = Range(0, 5)
scala> val range = (10 until 0) by -1
range: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
scala> val range = (10 until 0 by -1)
range: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
scala> val range = 10 until 0 by -1
range: scala.collection.immutable.Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
//方向是無(wú)法被推斷出來的
scala> val range = (10 until 0)
range: scala.collection.immutable.Range = Range()
scala> val range = (0 to 10)
range: scala.collection.immutable.Range.Inclusive = Range(0, 1, 2, 3, 4, 5, 6, 7
, 8, 9, 10)
scala> val range = 'a' to 'e'
range: scala.collection.immutable.NumericRange.Inclusive[Char] = NumericRange(a,
b, c, d, e)
begin to end
包括end
begin until end
不包括end
scala> 0 to 10
res0: scala.collection.immutable.Range.Inclusive = Range(0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10)
scala> 0 until 10
res1: scala.collection.immutable.Range = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
元組
元組是一個(gè)固定長(zhǎng)度的對(duì)象集合。元組中的對(duì)象可以具有不同類型。 在純函數(shù)式編程語(yǔ)言中,程序員經(jīng)常用元組便是對(duì)象以及它們的屬性。
scala> val person = ("Elvis", "Presley")
person: (String, String) = (Elvis,Presley)
scala> person._1
res2: String = Elvis
scala> person._2
res3: String = Presley
scala> person._3
<console>:13: error: value _3 is not a member of (String, String)
person._3
Scala使用元組而不是列表進(jìn)行多值賦值
scala> val (x, y) = (1, 2)
x: Int = 1
y: Int = 2
scala> val x,y = 1,2
<console>:1: error: ';' expected but ',' found.
val x,y = 1,2
^
元組具有固定長(zhǎng)度。
scala> val (a, b) = (1, 2, 4)
<console>:11: error: constructor cannot be instantiated to expected type;
found : (T1, T2)
required: (Int, Int, Int)
val (a, b) = (1, 2, 4)
5.2.5 Scala中的類
scala> class Person(firstName: String, lastName: String)
defined class Person
scala> new Person
<console>:13: error: not enough arguments for constructor Person: (firstName: St
ring, lastName: String)Person.
Unspecified value parameters firstName, lastName.
new Person
^
scala> new Person("xiaoming", "huang")
res9: Person = Person@7412a438
class Compass {
//{}內(nèi)的全部?jī)?nèi)容都是構(gòu)造函數(shù)的
val directions = List("north", "east", "south", "west")
var bearing = 0
print("Initial bearing: ")
println(directions)
def direction() = directions(bearing)
def inform(turnDirection: String) {
println("Turning " + turnDirection + ". Now bearing " + direction)
}
def turnRight() {
bearing = (bearing + 1) % directions.size
inform("right")
}
def turnLeft() {
bearing = (bearing + (directions.size - 1)) % directions.size
inform("left")
}
}
object App {
def main(args: Array[String]) {
val myCompass = new Compass
myCompass.turnRight()
myCompass.turnRight()
myCompass.turnLeft()
myCompass.turnLeft()
myCompass.turnLeft()
myCompass.turnLeft()
}
}
輔助構(gòu)造器
class Person(first_name: String) {
println("Outer constructor")
def this(first_name: String, last_name: String) {
this(first_name)
println("Inner constructor")
}
def talk() = println("Hi")
}
object Person{
def main(args: Array[String]) {
val bob = new Person("Bob")
val bobTate = new Person("Bob", "Tate")
}
}
5.2.6 擴(kuò)展類
1.伙伴對(duì)象和類方法
object TureRing {
def rule = println("To rule them all")
}
上面代碼創(chuàng)建了一個(gè)單件(singleton)對(duì)象。在Scala中,對(duì)象定義和類定義可以具有相同的名稱。可以在一個(gè)單件對(duì)象的聲明中創(chuàng)建類方法而在類聲明中創(chuàng)建實(shí)例方法。
2.繼承
class Person(val name: String) {
def talk(message: String) = println(name + " says " + message)
def id(): String = name
}
class Employee(override val name: String, val number: Int) extends Person(name) {
override def talk(message: String) {
println(name + " with number " + number + " says " + message)
}
override def id(): String = number.toString()
}
object App{
def main(args :Array[String]){
val employee = new Employee("Yoda", 4)
employee.talk("Extend or extend not. There is no try.")
}
}
無(wú)論是在構(gòu)造器中還是在任何擴(kuò)展基類的方法里,override
關(guān)鍵字都是必需的。
3. trait
一個(gè)對(duì)象可以擁有多種不同的角色。
可以將Scala的trait
看成是Java的接口外加一個(gè)接口的實(shí)現(xiàn)。
也可以將trait
看成是一個(gè)部分類的實(shí)現(xiàn)。
class Person(val name :String)
trait Nice {
def greet() = println("Howdily doodily.")
}
class Character(override val name :String) extends Person(name) with Nice
object App{
def main(args : Array[String]){
val flanders = new Character("Ned")
flanders.greet
}
}
5.2.7 第一天我們學(xué)到了什么
Scala的靜態(tài)類型是可以推斷出來的,用戶無(wú)需在任何場(chǎng)合都顯示聲明變量的類型,因?yàn)镾cala經(jīng)常可以根據(jù)語(yǔ)法線索推斷出這些類型。
編譯器也可以強(qiáng)制類型轉(zhuǎn)換,在合理的情況下,編譯器還允許隱式類型轉(zhuǎn)換。
Scala不支持類方法,而是使用了一種稱為伙伴對(duì)象的概念將同一個(gè)類的類方法和實(shí)例方法混在一起。
5.3 第二天:修建灌木叢和其他新把戲
//單行方法定義
scala> def double(x:Int):Int = x * 2
double: (x: Int)Int
scala> double(4)
res0: Int = 8
def
關(guān)鍵字既可以定義函數(shù)也可以定義方法。
//塊形式
scala> def double(x :Int):Int = {
| x * 2
| }
double: (x: Int)Int
scala> double(6)
res0: Int = 12
在返回類型Int
后面的=
是必需的。漏掉的話會(huì)出錯(cuò)。
5.3.1 對(duì)比var
和val
scala> var mutable = "I am mutable"
mutable: String = I am mutable
scala> mutable = "Touch me, change me..."
mutable: String = Touch me, change me...
scala> val immutable = "I am not mutable"
immutable: String = I am not mutable
scala> immutable = "Can't touch this"
<console>:12: error: reassignment to val
immutable = "Can't touch this"
^
var
變量的值是可變的,而val
變量的值是不變的。
在控制臺(tái)中,為方便起見,你可以多次重復(fù)定義一個(gè)變量,即使你使用的是val
。一旦你脫離控制臺(tái),重定義變量會(huì)引發(fā)一個(gè)錯(cuò)誤。
Scala引入var
風(fēng)格變量以支持傳統(tǒng)的命令式編程風(fēng)格,但是要避免使用var
。
可變狀態(tài)限制并發(fā)。
5.3.2 集合
函數(shù)式編程語(yǔ)言因其甚為好用的集合操作而聞名已久。
列表
scala> List(1, 2, 3)
res1: List[Int] = List(1, 2, 3)
scala> List("one", "tow", "three")
res2: List[String] = List(one, tow, three)
scala> List("one", "tow", 3)
res3: List[Any] = List(one, tow, 3)
scala> List("one", "tow", 3)(2)
res4: Any = 3
scala> List("one", "tow", 3)(4)
java.lang.IndexOutOfBoundsException: 4
at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65
)
at scala.collection.immutable.List.apply(List.scala:84)
... 32 elided
列表訪問是一個(gè)函數(shù),所以使用的是()
而不是[]
。
scala> List("one", "tow", 3)(-1)
java.lang.IndexOutOfBoundsException: -1
at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65
)
at scala.collection.immutable.List.apply(List.scala:84)
... 32 elided
scala> List("one", "tow", 3)(-2)
java.lang.IndexOutOfBoundsException: -2
at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65
)
at scala.collection.immutable.List.apply(List.scala:84)
... 32 elided
scala> List("one", "tow", 3)(-3)
java.lang.IndexOutOfBoundsException: -3
at scala.collection.LinearSeqOptimized$class.apply(LinearSeqOptimized.scala:65
)
at scala.collection.immutable.List.apply(List.scala:84)
... 32 elided
用負(fù)數(shù)作為下標(biāo),早期的Scala版本會(huì)返回列表的第一個(gè)元素。但是這種行為與表示下標(biāo)值過大的異常NoSuchElement
不一致,所以2.8.0版本修改了這種行為,讓它返回java.lang.IndexOutOfBoundsException
異常。
Nil
是一個(gè)空列表。
scala> Nil
res9: scala.collection.immutable.Nil.type = List()
2.集
scala> val animals = Set("lions", "tigers", "bears")
animals: scala.collection.immutable.Set[String] = Set(lions, tigers, bears)
scala> animals + "armadillos"
res10: scala.collection.immutable.Set[String] = Set(lions, tigers, bears, armadillos)
scala> animals - "tigers"
res11: scala.collection.immutable.Set[String] = Set(lions, bears)
scala> animals + Set("armadillos", "raccoons")
<console>:13: error: type mismatch;
found : scala.collection.immutable.Set[String]
required: String
animals + Set("armadillos", "raccoons")
^
集操作是沒有破壞性的。每個(gè)集操作都會(huì)建立一個(gè)新的集而不是修改舊的集。默認(rèn)情況下,集是不可改變的。
scala> animals ++ Set("armadillos", "raccoons")
res13: scala.collection.immutable.Set[String] = Set(bears, tigers, lions, armadillos, raccoons)
scala> animals -- Set("lions", "bears")
res14: scala.collection.immutable.Set[String] = Set(tigers)
交集
scala> animals & Set("armadillos", "raccoons", "lions", "tigers")
res16: scala.collection.immutable.Set[String] = Set(lions, tigers)
與列表不同,集與次序無(wú)關(guān)。
scala> Set(1, 2, 3) == Set(3, 2, 1)
res17: Boolean = true
scala> List(1, 2, 3) == List(3, 2, 1)
res18: Boolean = false
映射
scala> val ordinals = Map(0 -> "zero", 1 -> "one", 2 -> "tow")
ordinals: scala.collection.immutable.Map[Int,String] = Map(0 -> zero, 1 -> one,
2 -> tow)
scala> ordinals(2)
res19: String = tow
scala> import scala.collection.mutable.HashMap
import scala.collection.mutable.HashMap
scala> val map = new HashMap[Int, String]
map: scala.collection.mutable.HashMap[Int,String] = Map()
scala> map += 4 -> "four"
res20: map.type = Map(4 -> four)
scala> map += 8 -> "eight"
res21: map.type = Map(8 -> eight, 4 -> four)
scala> map
res22: scala.collection.mutable.HashMap[Int,String] = Map(8 -> eight, 4 -> four)
scala> map += "zeor" -> 0
<console>:14: error: type mismatch;
found : (String, Int)
required: (Int, String)
map += "zeor" -> 0
^
4.Any和Nothing
所有類都繼承自Any
,并且Nothing
類繼承自所有類。
5.3.3 集合與函數(shù)
高階函數(shù):一個(gè)以其他函數(shù)作為輸入?yún)?shù)或以函數(shù)作為返回結(jié)果的函數(shù)。
1.foreach
//代碼塊
variableName => yourCode
scala> val list = List("frodo", "samwise", "pippin")
list: List[String] = List(frodo, samwise, pippin)
scala> list.foreach(hobbit => println(hobbit))
frodo
samwise
pippin
scala> val hobbits = Set("frodo", "samwise", "pippin")
hobbits: scala.collection.immutable.Set[String] = Set(frodo, samwise, pippin)
scala> hobbits.foreach(hobbit => println(hobbit))
frodo
samwise
pippin
scala> val hobbits = Map("frodo" -> "hobbit", "samwise" -> "hobbit", "pippin" ->
"hobbit")
hobbits: scala.collection.immutable.Map[String,String] = Map(frodo -> hobbit, sa
mwise -> hobbit, pippin -> hobbit)
scala> hobbits.foreach(hobbit => println(hobbit))
(frodo,hobbit)
(samwise,hobbit)
(pippin,hobbit)
scala> hobbits.foreach(hobbit => println(hobbit._1))
frodo
samwise
pippin
scala> hobbits.foreach(hobbit => println(hobbit._2))
hobbit
hobbit
hobbit
2.更多列表方法
scala> list
res5: List[String] = List(frodo, samwise, pippin)
scala> list.isEmpty
res6: Boolean = false
scala> Nil.isEmpty
res7: Boolean = true
scala> list.length
res8: Int = 3
scala> list.size
res9: Int = 3
獲取列表的頭和尾對(duì)遞歸非常有用。
scala> list.head
res10: String = frodo
scala> list.tail
res11: List[String] = List(samwise, pippin)
scala> list.last
res12: String = pippin
scala> list.init
res13: List[String] = List(frodo, samwise)
scala> list
res14: List[String] = List(frodo, samwise, pippin)
scala> list.reverse
res15: List[String] = List(pippin, samwise, frodo)
scala> list.drop(1)
res16: List[String] = List(samwise, pippin)
scala> list
res17: List[String] = List(frodo, samwise, pippin)
scala> list.drop(2)
res18: List[String] = List(pippin)
3.計(jì)數(shù)、映射、過濾以及其他
scala> val words = List("peg", "al", "bud", "kelly")
words: List[String] = List(peg, al, bud, kelly)
scala> words.count(word => word.size > 2)
res19: Int = 3
scala> words.filter(word => word.size > 2)
res20: List[String] = List(peg, bud, kelly)
scala> words.map(word => word.size)
res21: List[Int] = List(3, 2, 3, 5)
scala> words.forall(word => word.size > 1)
res22: Boolean = true
scala> words.exists(word => word.size > 4)
res23: Boolean = true
scala> words.exists(word => word.size > 5)
res24: Boolean = false
scala> words.sortWith((s, t) => s.size < t.size)
res32: List[String] = List(al, peg, bud, kelly)
4. foldLeft
floadLeft
會(huì)將數(shù)組中的每個(gè)元素和另外的一個(gè)值傳遞給代碼塊。另外的值可以是初始值(在第一次調(diào)用代碼塊時(shí))也可以是從代碼塊中返回的結(jié)果。
initialValue /: List codeBlock
scala> words.sortWith((s, t) => s.charAt(0).toLower < t.charAt(0).toLower)
res34: List[String] = List(al, bud, kelly, peg)
scala> val sum = (0 /: list) {(sum, i) => sum + i}
sum: Int = 6
柯里化
函數(shù)式編程語(yǔ)言使用柯里化將一個(gè)帶有多個(gè)參數(shù)的函數(shù)轉(zhuǎn)換為多個(gè)擁有獨(dú)立參數(shù)列表的函數(shù)。
scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> list.foldLeft(0)((sum, value) => sum + value)
res35: Int = 6
5.3.4 第二天我們都學(xué)到了什么
編譯器嘗嘗能推斷出函數(shù)的返回類型,函數(shù)定義有單行和代碼塊兩種形式,并且參數(shù)列表可以改變。。
5.4 第三天:剪斷絨毛
5.4.1 XML
Scala將XML抬高到語(yǔ)言的一等編程結(jié)構(gòu)。
scala> var movies =
| <movies>
| <movie genre="action">Pirates of the Caribbean</movie>
| <movie genre="fairytale">Edward Scissorhands</movie>
| </movies>
movies: scala.xml.Elem =
<movies>
<movie genre="action">Pirates of the Caribbean</movie>
<movie genre="fairytale">Edward Scissorhands</movie>
</movies>
scala> movies.text
res36: String =
"
Pirates of the Caribbean
Edward Scissorhands
"
Scala內(nèi)置了一種與XPath類似的查詢語(yǔ)言,XPath是一種XML查詢語(yǔ)言。不過由于在Scala中,關(guān)鍵字//
是注釋的修飾符,Scala將使用\
和\\
。
scala> val movieNodes = movies \ "movie"
movieNodes: scala.xml.NodeSeq = NodeSeq(<movie genre="action">Pirates of the Caribbean</movie>, <movie genre="fairytale">Edward Scissorhands</movie>)
scala> val movieNodes = movies \\ "movie"
movieNodes: scala.xml.NodeSeq = NodeSeq(<movie genre="action">Pirates of the Caribbean</movie>, <movie genre="fairytale">Edward Scissorhands</movie>)
scala> movieNodes(0)
res37: scala.xml.Node = <movie genre="action">Pirates of the Caribbean</movie>
scala> movieNodes(0) \ "@genre"
res38: scala.xml.NodeSeq = action
5.4.2 模式匹配
object App{
def doChore(chore: String): String = chore match {
case "clean dishes" => "scrub, dry"
case "cook dinner" => "chop, sizzle"
case _ => "whine, complain"http://_是一個(gè)通配符
}
def main(args : Array[String]){
println(doChore("clean dishes"))
println(doChore("mow lawn"))
}
}
1.哨兵
object App{
def factorial(n: Int): Int= n match {
case 0 => 1
case x if x > 0 => factorial(n - 1) * n
}
def main(args : Array[String]){
println(factorial(3))
println(factorial(0))
}
}
2.正則表達(dá)式
Scala中的正則表達(dá)式是一等類型。針對(duì)一個(gè)字符串的.r
方法可以將任意字符串轉(zhuǎn)換成正則表達(dá)式。
scala> val reg = """^(F|f)\w*""".r
reg: scala.util.matching.Regex = ^(F|f)\w*
scala> println(reg.findFirstIn("Fantastic"))
Some(Fantastic)
scala> println(reg.findFirstIn("not Fantastic"))
None
用"""
為字符串劃定界限,允許多行字符串,去除了其內(nèi)部字符串的求職過程。.r
方法將字符串轉(zhuǎn)換為正則表達(dá)式。
scala> val reg = "the".r
reg: scala.util.matching.Regex = the
scala> reg.findAllIn("the way the scissors trim the hair and the shrubs")
res41: scala.util.matching.Regex.MatchIterator = non-empty iterator
scala> val matchs = reg.findAllIn("the way the scissors trim the hair and the shrubs")
matchs: scala.util.matching.Regex.MatchIterator = non-empty iterator
scala> matchs.foreach(it => println(it))
the
the
the
the
3.XML和匹配
import scala.xml
object App{
def main(args : Array[String]){
val movies = <movies>
<movie>The Incredibles</movie>
<movie>WALL E</movie>
<short>Jack Jack Attack</short>
<short>Geri's Game</short>
</movies>
(movies \ "_").foreach{ movie =>
movie match {
case <movie>{movieName}</movie> => println(movieName)
case <short>{shortName}</short> => println(shortName + "(short)" )
}
}
}
}
5.4.3 并發(fā)
包括actor和消息傳遞。actor擁有線程池和隊(duì)列池。當(dāng)發(fā)送一條消息給actor時(shí)(使用!
操作符),是將一個(gè)對(duì)象放到該actor的隊(duì)列中。actor讀取消息并采取行動(dòng)。通常情況下,actor通過模式匹配器去檢測(cè)消息并執(zhí)行相應(yīng)的消息處理。
import scala.actors.Actor
case object Poke
case object Feed
class Kid() extends Actor {
def act() = {
loop {
react {
case Poke => {
println("Ow...")
Thread.sleep(2000)
println("Quit it...")
}
case Feed => {
println("Gurgle...")
Thread.sleep(2000)
println("Burp...")
}
}
}
}
}
object App {
def main(args: Array[String]) {
val bart = new Kid().start
val lisa = new Kid().start
bart ! Poke
lisa ! Poke
bart ! Feed
lisa ! Feed
}
}
Kid
是actor,這意味著它將在線程池中的某個(gè)線程中運(yùn)行,并從一個(gè)隊(duì)列中讀取消息。它將一個(gè)接一個(gè)地處理每條消息。react
可以接收來自actor的消息。
使用actor,可以設(shè)置超時(shí)處理(reactWithin
),當(dāng)在指定時(shí)間內(nèi)沒有接收到消息時(shí),會(huì)觸發(fā)超時(shí)處理。使用receive
(它將阻塞線程)和receiveWithin
(它將在設(shè)置的超時(shí)時(shí)間內(nèi)阻塞線程)。
5.4.4 實(shí)際中的并發(fā)
import scala.io._
import scala.actors._
import Actor._
object App {
object PageLoader {
def getPageSize(url: String) = Source.fromURL(url).mkString.length
}
val urls = List("http://www.baidu.com/",
"http://www.lxweimin.com/",
"http://www.youdao.com/",
"http://www.sina.com.cn/")
def timeMethod(method: ()=> Unit) = {
val start = System.nanoTime()
method()
val end = System.nanoTime()
println("Method took " + (end - start)/1000000000.0 + " seconds." )
}
def getPageSizeSequentially() = {
for (url <- urls) {
println("Size for " + url + ":" + PageLoader.getPageSize(url))
}
}
def getPageSizeConcurrently() = {
val caller = self
for (url <- urls) {
actor { caller !(url, PageLoader.getPageSize(url))}
}
for (i <- 1 to urls.size) {
receive {
case (url, size) =>
println("Size for " + url + ": " + size)
}
}
}
def main(args: Array[String]) {
println("Sequential run:")
timeMethod{getPageSizeSequentially}
println("Concurrent run:")
timeMethod{getPageSizeSequentially}
}
}
5.4.5 第三天我們學(xué)到了什么
actor
是為并發(fā)而構(gòu)建出來的對(duì)象。通常擁有一個(gè)包含react
或receive
方法的循環(huán),用于接收發(fā)給該對(duì)象的隊(duì)列消息。
5.5 趁熱打鐵
Scala使用的是靜態(tài)類型策略。
5.5.1核心優(yōu)勢(shì)
1.并發(fā)
無(wú)需可變狀態(tài)的并發(fā)應(yīng)用設(shè)計(jì)能力
不變性是為改善并發(fā)代碼設(shè)計(jì)能夠做的唯一的、最重要的事情。
2. 遺留Java的演化
Scala應(yīng)用可以直接使用Java庫(kù),并且在必要時(shí)可以使用代理對(duì)象的代碼生成功能,與Java的互操作行非常好。
創(chuàng)立新的編程社區(qū)的最好方法就是充分接受現(xiàn)有的社區(qū)。
代碼塊成為了語(yǔ)言的一等類型構(gòu)造,并且可以與核心集合庫(kù)很好地集成在一起使用。
3. 領(lǐng)域特定語(yǔ)言
Scala靈活語(yǔ)法和操作符重載
操作符只是簡(jiǎn)單的方法聲明
4.XML
Scala提供內(nèi)置的XML支持。模式匹配使得各種不同的XML結(jié)構(gòu)的解析塊易于使用。將XPath語(yǔ)法集成到復(fù)雜的XML中使得代碼變得更為簡(jiǎn)單、可讀。
5.橋接
函數(shù)式編程模式很重要,因?yàn)樗梢院芎玫靥幚聿l(fā),并且處理器的并發(fā)程度也越來越高。
5.5.2 不足之處
Scala的語(yǔ)法要求過多且偏學(xué)術(shù)性。
1. 靜態(tài)類型
靜態(tài)類型天生適合函數(shù)式編程語(yǔ)言,但是對(duì)于面向?qū)ο笙到y(tǒng)就是災(zāi)難
2.語(yǔ)法
構(gòu)造器 new Person
而不是Person.new
參數(shù)類型setName(name: String)而不是setName(String name)
返回類型從Java方法聲明的開頭處挪到了結(jié)尾處。
3. 可變性
可變性可能導(dǎo)致各種各樣的并發(fā)bug。