自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Scala語言編程入門指南

開發(fā) 后端
本文為《Programming Scala》的中文譯文《Scala 編程指南》,經(jīng)51CTO與本文譯者聯(lián)系認(rèn)可,51CTO將連載《Scala 編程指南》的新鮮譯文,供Scala學(xué)習(xí)者學(xué)習(xí)。

《Programming Scala》由O'reilly出版社出版,是一本開放的、不用于商業(yè)用途的Scala語言學(xué)習(xí)讀物,與51CTO讀書頻道介紹的《Scala程序設(shè)計: Java虛擬機多核編程實戰(zhàn)》雖然不同,但是有異曲同工之妙,原文地址為:programming-scala.labs.oreilly.com/ 。本文為《Programming Scala》***章譯文,從Scala語言編程入門介紹開始。

51CTO推薦專題:Scala編程語言

***章 從0分到60分:Scala 介紹

為什么選用 Scala

當(dāng)今的企業(yè)和互聯(lián)網(wǎng)應(yīng)用程序必須平衡一系列的要點。它們要有快速而可靠的實現(xiàn)。新的功能要能在短時間內(nèi)通過周期漸進的方式加入。除了簡單地提供商務(wù)邏輯之外,應(yīng)用程序必須支持訪問安全控制,數(shù)據(jù)持久化,事務(wù),和其它的進階功能。程序必須高度易用和可擴展,同時要求支持并發(fā)和分布式計算。應(yīng)用程序會被網(wǎng)絡(luò)化,并且提供人和機器都易于使用的接口。

要達成這些挑戰(zhàn),許多軟件開發(fā)者在尋找新型的編程序言和工具。以往備受推崇的如:Java,C#,和C++ 已經(jīng)不再是開發(fā)這些次世代應(yīng)用程序的***候選。

如果你是一個Java 程序開發(fā)者

Java 是由Sun 公司在1995 年,互聯(lián)網(wǎng)高速發(fā)展的時候正式引入的。 由于當(dāng)時需要一個安全的,可移植的,開發(fā)者友好的程序語言,它被迅速地推崇為編寫瀏覽器應(yīng)用的理想語言。而當(dāng)時的主流語言,C++,則并不適合這個領(lǐng)域。

今天,Java 被更多地使用在服務(wù)器端程序中。它是開發(fā)網(wǎng)絡(luò)和企業(yè)應(yīng)用的***的語言之一。

然而,Java 是它們那個時代的產(chǎn)物,至今也有一定年代了。在1995年,Java 為了拉攏C++開發(fā)者,提供了和C++ 足夠相似的語法,同時也避開了C++ 語言上的缺陷和危險。Java 采納了絕大多數(shù)那個時代對解決軟件開發(fā)問題有用的概念,比如面向?qū)ο缶幊蹋∣OP), 同時也丟棄了一些麻煩的充滿問題的技術(shù),比如人工的內(nèi)存控制。這些設(shè)計決策在最小化復(fù)雜度和***化開發(fā)生產(chǎn)力上達到了一個優(yōu)異的平衡。然而,從Java 出生演化到現(xiàn)在,許多人認(rèn)為它變得越來越復(fù)雜,而且并沒有顯著地解決新的程序開發(fā)過程中面臨的問題和挑戰(zhàn)。

程序開發(fā)者想要一種更精煉和更靈活的語言去提高他們的生產(chǎn)效率。這也是如今所謂的Ruby ,Python 這樣的腳本(Script)語言大行其道的原因之一。

永無休止的需求驅(qū)動著架構(gòu)向大規(guī)模并發(fā)開發(fā)進行。然而,Java 的并發(fā)模型是基于對共享的,可變的信號狀態(tài)的同步存取,從而導(dǎo)致了復(fù)雜的,易錯的程序。

當(dāng)Java 漸漸老化時,運行它的 Java 虛擬機(JVM)卻持續(xù)地散發(fā)著光芒。如今JVM 的性能優(yōu)化是非凡的,它允許字節(jié)碼(byte code)在許多情況下得到和本地編譯的代碼相同的性能。今天,許多程序開發(fā)者相信使用基于JVM 的新語言是正確的前進道路。Sun 顯然是擁護這個趨勢的,他們雇傭了JRuby 和Jython (Ruby 和Python 在JVM 上的實現(xiàn))的主要開發(fā)者。

Scala 的出現(xiàn)對于Java 開發(fā)者來說提供了一個更加新式的語言。同時保留了JVM 的驚人的性能和開發(fā)了十幾年的Java 庫的寶貴財富。

如果你是一個Ruby,Python 的開發(fā)者

像Ruby,Python,Groovy,JavaScript,和Smalltalk 這樣的動態(tài)類型語言,通常因為它們優(yōu)雅的靈活性,強大的元編程能力(metaprogramming),提供了很高的生產(chǎn)力。

如果撇開它們在高產(chǎn)能上的優(yōu)勢,動態(tài)語言也許不是個萬金油,特別對于大規(guī)模和高性能程序來說,不是***選擇。在編程社區(qū)里,有一個對于動態(tài)類型和靜態(tài)類型究竟誰更占有優(yōu)勢進行的冗長爭論。很多的比較觀點多少都有些主觀。我們不會在這里討論所有的這些爭論,但是我們會提供一些對此的看法以供參考。

相比靜態(tài)語言來說,優(yōu)化動態(tài)語言的性能更富有挑戰(zhàn)性。在靜態(tài)語言中,優(yōu)化器可以根據(jù)類型信息來進行決策。而在動態(tài)語言中,只有很有限的信息是可用的,這使得優(yōu)化器的選擇更加困難。雖然近年來在動態(tài)語言優(yōu)化方面的提升漸漸浮現(xiàn)希望,但是它們還是落在靜態(tài)語言的優(yōu)化藝術(shù)的后面。所以,如果你確實需要很高的性能,靜態(tài)語言或許是一個更保險的選擇。

靜態(tài)語言同樣可以使開發(fā)過程獲得好處。集成開發(fā)環(huán)境(IDE)的一些功能,比如自動完成(有時候被稱為智能感知)在靜態(tài)語言中更容易完成,因為那些類型信息都是可用的。而更加明顯的類型信息在靜態(tài)代碼中促進了代碼的自我解釋,隨著項目的發(fā)展,這對于開發(fā)者意圖的互相交流是十分重要的。

當(dāng)使用一種靜態(tài)語言時,你必須時刻考慮使用恰當(dāng)?shù)念愋汀_@迫使你在選擇設(shè)計時更加小心。這雖然會拖慢日常的設(shè)計決策,但是長此以往,在應(yīng)用程序中對類型使用的思考會帶來更為清晰的設(shè)計。

靜態(tài)語言的另外一個小的好處就是編譯時期的額外檢查。我們通常認(rèn)為這個優(yōu)勢被夸大了,因為類型不匹配的錯誤只是日常見到的運行時錯誤中的一小部分。編譯器無法發(fā)現(xiàn)邏輯錯誤,這顯然更加重要。只有一個綜合的,自動的測試組可以發(fā)現(xiàn)邏輯錯誤。對于動態(tài)語言來說,測試也必須覆蓋可能的類型錯誤。如果你以前編寫過動態(tài)類型語言,你會發(fā)現(xiàn)你的測試組其實會小一些,但不會小很多。

許多開發(fā)者發(fā)現(xiàn)靜態(tài)語言太過冗長,抱怨靜態(tài)類型是冗長的元兇,而事實上真正的原因是缺少類型推斷。在類型推斷的情況下,編譯器會根據(jù)上下文推斷值的類型。例如,編譯器會識別在 x = 1 + 3 中x 是一個整型。類型推斷能顯著地減少代碼的長度,使得代碼更像是用動態(tài)語言編寫出來的。

我們都曾經(jīng)在不同的時間和靜態(tài)語言和動態(tài)語言打過交道。我們發(fā)現(xiàn)兩種類型的語言都因為不同的原因被廣為關(guān)注。我們相信現(xiàn)代軟件開發(fā)者必須掌握一系列的語言和工具。有時,動態(tài)語言會是完成工作的正確工具;而有時,一個靜態(tài)語言,例如Scala,會是你正需要的。

#p#

Scala 介紹

Scala 是一種迎合現(xiàn)代軟件開發(fā)者需求的語言。它是靜態(tài)的,混合范式的(mixed-paradigm),基于JVM 的語言;它在擁有簡潔,優(yōu)雅,靈活的語法的同時,也提供了一個久經(jīng)考驗的類型系統(tǒng)和慣用語法,所以從小巧的解釋性腳本到大型的復(fù)雜系統(tǒng)它都可以勝任。那可是一大口蛋糕,所以,讓我們詳細(xì)地來了解下它的一些特性。

靜態(tài)類型

正如我們在前面的章節(jié)所描述的,一個靜態(tài)類型的語言在一個變量的生命周期內(nèi)都會綁定一個類型。相反的,動態(tài)類型的語言則是根據(jù)變量所引用的值來綁定類型,這意味著變量的類型可以隨著它引用的值改變而改變。

在***的基于JVM 的語言中,Scala 是為數(shù)不多的靜態(tài)類型語言,而且是最出名的一個。

混合范式 - 面向?qū)ο缶幊?/strong>

Scala 完全支持面向?qū)ο缶幊蹋∣OP)。Scala 在改進Java 對OOP 的支持的同時,添加了traits (特性)的概念,它可以簡潔地實現(xiàn)類之間的混合關(guān)系。Scala 的traits 和Ruby 的modules (模塊)概念類似。如果你是一個Java 開發(fā)者,可以把traits 想象成interfaces (接口)和implementations (實現(xiàn))的統(tǒng)一體。

在Scala 中,所有的東西實際上都是一個object (對象)。Scala 不像Java,它沒有原始類型(元數(shù)據(jù)類型)。相反的,所有的數(shù)值類型都是正真的objects。 然而,為了優(yōu)化性能,Scala 會實時地在底層實現(xiàn)中使用原始類型。另外,Scala 不支持static (靜態(tài))或者class-level members (類級別成員)的類型,因為它們并沒有和一個實例(instance)關(guān)聯(lián)。相反,Scala 支持單例模式,可以應(yīng)用于那些一種類型只有一個實例的情況。

混合范式 - 函數(shù)式編程

Scala 完全支持函數(shù)式編程(FP)。FP 是一種比OOP 更加古老的編程范式,它被學(xué)術(shù)界的象牙塔庇護至今。FP 因為簡化了某些設(shè)計,尤其是并發(fā)上的問題而受到了越來越多的關(guān)注。“純粹”的函數(shù)式語言不允許任何易變狀態(tài)(mutable state),因而避免了對易變狀態(tài)的同步和共享訪問。相反的,用純函數(shù)式語言編寫的程序在并發(fā)自主的進程中通過傳遞消息來通信。Scala 通過Actors 庫來支持這種模式,但是它同時允許mutable (易變的)和immutable (不易變的)變量。

函數(shù)是FP 的一類公民,這意味著它們可以被賦值給變量,被傳遞給其他函數(shù)等,就像普通的值一樣。這個特色允許通過元操作來組合一些高級行為。因為Scala 遵守所有的東西都是object 的原則,函數(shù)在Scala 中也是objects。

Scala 同時支持閉包,一種動態(tài)語言比如Python 和Ruby 從函數(shù)式編程世界中引用過來的特性。Java 很遺憾地沒有在最近的版本中包含這個特性。閉包本質(zhì)上是一個函數(shù)和其引用的變量的統(tǒng)一定義。這些變量不作為傳入?yún)?shù)或者函數(shù)內(nèi)的局部變量。一個閉包封閉了這些引用,所以函數(shù)調(diào)用可以安全的引用這些變量,即使它們已經(jīng)超出了函數(shù)的作用域。閉包是一個強大的抽象,以至于objects 系統(tǒng)和基礎(chǔ)控制結(jié)構(gòu)經(jīng)常是用它們實現(xiàn)的。

一種同時有JVM 和.NET 實現(xiàn)的語言

Scala 是眾所周知的基于JVM 的語言,這意味著Scala 會生成JVM 字節(jié)碼。一個能生成CLR 字節(jié)碼的基于.NET 的Scala 版本也同時在開發(fā)中。當(dāng)我們提到底層的“運行時”時,我們通常是指JVM。但是許多我們提到的概念能同時運用于兩種不同的運行時。當(dāng)我們討論有關(guān)JVM 的細(xì)節(jié)時,它們大致也能應(yīng)用于.NET,除非我們特別說明。

Scala 的編譯器使用了一些聰明的技巧來映射Scala 的擴展到相應(yīng)的字節(jié)碼。在Scala 里,我們可以輕松地調(diào)用產(chǎn)生自Java 源代碼(JVM)或者C# 源代碼(.NET)的字節(jié)碼。同樣的,你也可以在Java,C# 代碼里調(diào)用Scala。運行在JVM 和CLR 上,允許Scala 開發(fā)者來充分利用現(xiàn)有的庫來和運行在這些運行時的其他語言交互。

簡潔的,優(yōu)雅的,靈活的語法

Java 的語法實際上有些冗長。 Scala 使用了一些技巧來減少不必要的語法,使得Scala 源碼幾乎和其他的動態(tài)語言一樣簡潔。類型推斷使得顯式的類型聲明信息在大多數(shù)場合下減少到了***。類型和函數(shù)的聲明變得非常簡潔。

Scala 允許函數(shù)名字包含非字母數(shù)字的字符。結(jié)合一些語法上的技巧,這些特性允許用戶定義一些看起來像操作符的方法。這樣,在語言核心之外的庫對于用戶看來就會比較自然。

復(fù)雜的類型系統(tǒng)

Scala 擴展了Java 的類型系統(tǒng),同時提供了更靈活的類型和一些高級的類型結(jié)構(gòu)。這個類型系統(tǒng)起初開起來可能會有些恐怖,但是大多數(shù)時候你不用擔(dān)心這些高級的結(jié)構(gòu)。類型推斷幫助你自動推斷類型簽名,所以用戶不用人工提供一般的類型信息。不過,當(dāng)你需要它們的時候,高級類型特性可以給你提供更靈活的方式,用類型安全的方式解決設(shè)計上的問題。

可伸縮性 - 架構(gòu)

Scala 被設(shè)計來服務(wù)從小的,解釋性腳本到大型的,分布式系統(tǒng)。Scala 提供了4 種語言機制來提供更靈活的系統(tǒng)組合:1)顯式的自我類型(selftype),2)類型成員和種類的抽象,3)嵌套的類,以及4)使用traits 的混合結(jié)構(gòu)。

沒有其它的語言同時提供所有這些機制了。這些機制一起允許用一種類型安全和簡潔的方式來構(gòu)建由可重用組件組成的程序。正如我們所見,許多常見的設(shè)計模式和架構(gòu)技術(shù),例如依賴注入模式,可以容易地用Scala 來實現(xiàn),而不用冗長的樣板代碼或者XML 配置文件 -- 它們經(jīng)常讓Java 開發(fā)變得很枯燥。

可伸縮性 - 性能

因為Scala 代碼運行在JVM 和CLR 上,它能獲得所有來自這些運行時和支持性能靈活性調(diào)整的第三方工具的性能優(yōu)化,例如分析器(profiler),分布式緩存庫,集群機制等。如果你相信Java 和C# 的性能,那么你就能信任Scala 的性能。當(dāng)然,一些特別的結(jié)構(gòu)在這個語言環(huán)境下和某些庫中相比其它語言會運行地特別高效或者低效。一如既往的,你應(yīng)該在必要的時候分析和優(yōu)化你的代碼。

表面上看起來OOP 和FP 像是不兼容的。但實際上,Scala 的設(shè)計哲學(xué)是OOP 和FP 應(yīng)該協(xié)同合作而不是對立。其中一方的特性應(yīng)該能增強另一方。

在FP 里,函數(shù)沒有副作用,變量都是不易變的。而在OOP 中,可變狀態(tài)和副作用都十分常見,甚至是被鼓勵的。Scala 讓你來選擇解決設(shè)計問題***的方式。函數(shù)式編程對于并發(fā)特別有用,因為它摒棄了對易變狀態(tài)的同步訪問。然而,“純”函數(shù)式語言是十分嚴(yán)格的。有一些設(shè)計問題還是使用易變對象比較容易解決。

Scala 的名字來自詞語:可伸縮的語言(scalable language)的縮寫。這就建議Scala 的發(fā)音為scale-ah,實際上Scala 的創(chuàng)建者發(fā)音為scah-lah,像意大利語中的“stairs”(樓梯)。也就是說,兩個“a 的”的發(fā)音是一樣的。

Martin Oderskey  的在計算機語言方面的背景和經(jīng)驗是顯著的。在你學(xué)習(xí)Scala 的時候,你會了解這是一個仔細(xì)考慮了設(shè)計決策,利用了所有類型理論,OOP 和FP 的藝術(shù)的語言。Martin 在JVM 方面的經(jīng)驗對于Scala 和JVM 平臺的優(yōu)雅結(jié)合有著顯著的幫助。它綜合了OOP 和FP 的優(yōu)點,是一個優(yōu)秀的兩全其美的解決方案。

Scala 的誘惑

今天,我們的產(chǎn)業(yè)幸運地?fù)碛性S多語言方面的選擇。動態(tài)語言的能力,靈活性,優(yōu)雅已經(jīng)使它們十分流行。但是,Java 和.NET 庫,已經(jīng)JVM 和CLR 的性能作為珍貴的寶藏,符合了許多實際的企業(yè)和互聯(lián)網(wǎng)項目的需求。

Scala 引起眾人的興趣是因為它的簡潔語法和類型推斷,看起來像動態(tài)腳本語言。但是,Scala 提供了所有靜態(tài)類型的優(yōu)勢,一個現(xiàn)代的對象模型,函數(shù)式編程,和先進的類型系統(tǒng)。這些工具允許你建立一個可伸縮的,模塊化的應(yīng)用程序,并且重用之前的Java 和.NET API, 充分利用JVM 和CLR 的性能。

Scala 是面向?qū)I(yè)開發(fā)者的語言。相比較與Java 和Ruby,Scala 更難掌握。因為它要求OOP,F(xiàn)P 和靜態(tài)類型方面的技能,這樣才能更高效地使用它。它誘使我們偏愛動態(tài)語言的相對簡潔。但是,這種簡潔是一種假象。在一種動態(tài)類型語言中,使用元編程特性來實現(xiàn)高級設(shè)計經(jīng)常是必要的。元編程十分強大,但是使用它需要經(jīng)驗,而且會導(dǎo)致代碼變得難以理解,維護和調(diào)試。在Scala 中,許多類似的設(shè)計目標(biāo)可以通過類型安全的方式來達到,利用它的類型系統(tǒng)和通過traits 實現(xiàn)的混合結(jié)構(gòu)。

我們覺得在Scala 的日常使用中所需求的額外努力會迫使我們在設(shè)計時更加謹(jǐn)慎。久而久之,這樣的幾率會導(dǎo)致更加清晰的,模塊化的,可維護的系統(tǒng)。幸運的是,你不必所有時候都去追逐Scala 所有復(fù)雜的功能。你的大多數(shù)代碼會簡單清晰,就像是用你最喜歡的動態(tài)語言寫出來的一樣。

另外一個策略是聯(lián)合幾種簡單的語言,比如Java 來做面向?qū)ο蟮拇a,Erlang 來做函數(shù)式,并發(fā)的代碼。這樣一個分解會工作的很好,如果你的系統(tǒng)能清晰地分解成這些不想關(guān)聯(lián)的部分,并且你的團隊能掌控這樣一個混雜的環(huán)境。Scala 對于那些僅需要一個全能語言的情況是***吸引力的。也就是說,Scala 代碼可以和諧地與其他語言共處,尤其是基于JVM 和.NET 的語言。

#p#

安裝 Scala

這個章節(jié)描述了如何安裝Scala 的命令行工具, 以便可以盡快讓Scala 跑起來,這也是運行本書所有范例的必要充分條件。在各種編輯器和集成開發(fā)環(huán)境(IDE)中使用Scala 的細(xì)節(jié),請參見和IDE 集成,在第14章-Scala 工具,庫和IDE 支持。本書的范例是用Scala 版本2.7.5.final 來編寫和編譯, 也是本書在編寫時候的***的發(fā)行版;也有部分是用Scala 版本2.8.0 的每夜編譯版本,當(dāng)你讀到這本書的時候應(yīng)該已經(jīng)最終完成了。

注意

2.8 版本引入了很多新的特性,我們會在這本書中予以強調(diào)。

我們在這本書中會選用JVM 版本的Scala。 首先,你必須安裝Java 1.4 或更高的版本(推薦1.5 或更高)。如果你需要安裝Java,請登錄,按照指示在你的電腦上安裝Java。

Scala 的官方網(wǎng)站 。要安裝Scala,去到下載(downloads)頁面 。按照下載頁面上的指示下載適合你系統(tǒng)環(huán)境的安裝包。

最簡單的跨平臺安裝包是IzPack 安裝器。下載Scala 的jar (譯注:編譯完以后的Java 專屬格式)文件,可以選擇scala-2.7.5.final-installer.jar 或者 scala-2.8.0.N-installer.jar, N在這里是2.8.0 版本的***發(fā)布版本。在終端窗口中(譯注:或者Windwos 下的命令行),定位到下載的目錄,使用java 命令來安裝Scala。假設(shè)你下載了scala-2.8.0.final-installer.jar,運行如下命令會帶領(lǐng)你完成安裝過程。

  1.  
  2.  
  3. java -jar scala-2.8.0.final-installer.jar  

提示

在蘋果系統(tǒng)下(Mac OS X),安裝Scala 的最簡單方式是使用MacPorts。按照這個頁面的安裝指示,然后使用 sudo port insall scala. 不用幾分鐘你就可以運行Scala 了。

在本書中,我們會使用符號scala-home 來指定Scala 安裝路徑的根目錄。

注意

在Unix,Linux,和Mac OS X 系統(tǒng)下,你需要root 用戶權(quán)限,或者sudo 命令才能把Scala 安裝在一個系統(tǒng)目錄下。比如:

  1. scala-home = /usr/local/scala-2.8.0.final. 

或者,你也可以下載并且展開壓縮過的tar 文件(比如scala-2.8.0.final.tgz)或者zip 文件(scala-2.8.0.final.zip)。在類Unix 系統(tǒng)中,展開壓縮文件到一個你選擇的路徑。然后,把scala-home/bin 子目錄加入到你的PATH 環(huán)境變量中。例如,如果你安裝到 /usr/local/scala-2.8.0.final,那么把/usr/local/scala-2.8.0.final/bin 加入到PATH。

要測試你的安裝,在命令行下運行如下命令:

  1.  
  2.  
  3. scala -version  

我們會在后面學(xué)習(xí)如何使用scala 命令行。你應(yīng)該能獲得如下輸出:

  1.  
  2.  
  3. Scala code runner version 2.8.0.final -- Copyright 2002-2009, LAMP/EPFL  

當(dāng)然,你看到的版本號會根據(jù)你安裝的版本而改變。從現(xiàn)在起,當(dāng)我們展示命令行輸出時候如果包含版本號,我們會使用2.8.0.final。

祝賀你,你已經(jīng)安裝了Scala!如果你在運行scala 后獲得一個錯誤消息:command not found(無法找到命令),重新檢查你的PATH 環(huán)境變量,確保它被正確地設(shè)立,并包含了正確的bin 目錄。

注意

Scala 2.7.X 以及之前的版本和JDK 1.4 以及更新的版本兼容。Scala 2.8 版本舍棄了1.4 的兼容性。注意Scala 會使用原生的JDK 類庫,比如String 類。在.NET 下,Scala 使用對應(yīng)的.NET 類。

同時,你應(yīng)該能在那個下載頁面找到Scala API 文檔和源碼的下載鏈接。

更多信息

在探索Scala 的時候,你會在這個網(wǎng)頁上發(fā)現(xiàn)有用的資源。你會發(fā)現(xiàn)開發(fā)支持工具和庫的鏈接,還有教程,語言規(guī)范【ScalaSpec2009】,和描述語言特性的學(xué)術(shù)論文。

Scala 工具和API 的文檔特別有用。你可以在這個頁面瀏覽API 文檔。這個文檔是使用scaladoc 工具生成的,類似于Java 的javadoc 工具。參見第14章- Scala 工具,庫和IDE支持的“scaladoc 命令行工具”來獲得更多的信息。

你也可以在下面頁面下載一個API 文檔的壓縮文件來本地瀏覽?;蛘吣憧梢杂胹baz 工具來安裝,如下

  1. sbaz install scala-devel-docs 

sbaz 和scala,scalac 命令行工具安裝同樣的bin 目錄下。安裝的文檔也同樣包含了scala 工具集(包括sbaz)的細(xì)節(jié)和代碼示例。要獲取更多Scala 命令行工具和其他資源的信息,參見第14章- Scala 工具,庫和IDE 支持。

#p#

初嘗 Scala

是時候用一些實在的Scala 代碼來刺激一下你的欲望了。在下面的范例中,我們會描述足夠的細(xì)節(jié)讓你明白發(fā)生了什么。這一節(jié)的目標(biāo)是給你一個大致概念,讓你知道用Scala 來編程是怎么一回事。我們會在以后的各個章節(jié)來探索Scala 更多的特性。

作為***個實例,你可以用兩種方式來運行它:交互式的,或者作為一個“腳本”。

讓我們從交互式模式開始。我們可以通過在命令行輸入scala,回車,來啟動scala 解釋器。你會看到如下輸出。(版本號可能會有所不同。)

  1. Welcome to Scala version 2.8.0.final (Java ...).  
  2. Type in expressions to have them evaluated.  
  3. Type :help for more information.  
  4. scala> 

***一行是等待你輸入的提示符。交互式的scala 命令對于實驗來說十分方便(參見《第14章-Scala工具,庫和IDE支持》的“Scala 命令行工具”章節(jié),來獲取更多信息)。一個像這樣的交互式解釋器被稱為REPL:讀(Read),評估(Evaluate),打?。≒rint),循環(huán)(Loop)

輸入如下的兩行代碼。

  1. val book = "Programming Scala" 
  2. println(book) 

實際上的輸入和輸出看起來會像是這樣。

  1. scala> val book = "Programming Scala" 
  2. book: java.lang.String = Programming Scala  
  3. scala> println(book)  
  4. Programming Scala  
  5. scala> 

在***行我們使用了val 關(guān)鍵字來聲明一個只讀變量 book。注意解釋器的輸出顯示了book 的類型和值。這對理解復(fù)雜的聲明會很方便。第二行打印出了book 的值 -- Programming Scala。

提示

在交互模式(REPL)模式下來測試scala 命令是學(xué)習(xí)Scala 細(xì)節(jié)的一個非常好的方式。

這本書里的許多例子可以像這樣在解釋器里運行。然而,通常使用我們提到的第二個方式會更加方便:在文本編輯器中或者IDE 中編寫Scala 腳本,然后用同樣的scala 命令來執(zhí)行它們。我們會在這章余下的絕大多數(shù)部分使用這種方式。

用你選擇的文本編輯器,保存下面例子中的Scala 代碼到一個名為upper1-script.scala 的文件,放在你選擇的目錄中。

  1. // code-examples/IntroducingScala/upper1-script.scala  
  2. class Upper {  
  3.   def upper(strings: String*): Seq[String] = {  
  4.     strings.map((s:String) => s.toUpperCase())  
  5.   }  
  6. }  
  7. val up = new Upper  
  8. Console.println(up.upper("A", "First", "Scala", "Program")) 

這段Scala 腳本把一個字符串轉(zhuǎn)換到大寫。

順便說一下,在***行有一句注釋(在代碼例子中是源文件的名字)。Scala 使用和Java,C#,C++等一樣的注釋方式。一個// 注釋會影響整個一行,而/* 注釋 */ 方式則可以跨行。

要運行這段腳本,打開命令行窗口,定位到對應(yīng)目錄,然后運行如下命令。

  1. scala upper1-script.scala 

文件會被解釋,這意味著它會被編譯和執(zhí)行。你會獲得如下輸出:

  1. Array(A, FIRST, SCALA, PROGRAM) 

解釋 VS 編譯,運行Scala 代碼

總的來說,如果你在命令行輸入scala 而不輸入文件名參數(shù),解釋器會運行在交互模式。你輸入的定義和語句會被立即執(zhí)行。如果你附帶了一個scala 文件作為命令參數(shù),它會把文件作為腳本編譯和運行,就像我們的 scala upper1-script.scala 例子一樣。***,你可以單獨編譯scala 文件,運行class 文件,只要你有一個main 函數(shù),就像你通常使用java 命令一樣。(我們會馬上給出一個例子)

你需要理解有關(guān)使用解釋模式的局限和單獨編譯運行之間的一些微妙的區(qū)別。我們會在《第14章- Scala 工具,庫和IDE 支持》的“命令行工具”部分詳細(xì)解釋這些區(qū)別。

當(dāng)我們提及執(zhí)行一個腳本時,就是說用scala 命令運行一個Scala 源文件。

在這個例子里,類Upper (字面意思,沒有雙關(guān)) 里的upper 函數(shù)把輸入字符串轉(zhuǎn)換為大寫,然后作為一個數(shù)組返回。***一行把4個字符串轉(zhuǎn)換完以后輸出。

為了學(xué)習(xí)Scala 語法,讓我們來更詳細(xì)地解釋一下代碼。在這僅有的6行代碼里面有許多細(xì)節(jié)!我們會解釋一下基礎(chǔ)的概念。這個例子的所有的概念會在這被書的后面幾個章節(jié)被詳細(xì)地講解。

在這個例子里,Upper 類以class 關(guān)鍵字開始。類的主體被概括在最外面的大括號中 {...}。

upper 方法的定義在二行,以def 關(guān)鍵字開始,緊接著是方法名,參數(shù)列表,和方法的返回類型,***是等于號“=”,和方法的主體。

在括號里的參數(shù)列表實際上是一個String(字符串)類型的可變長度參數(shù)列表,由冒號后面后面的String* 類型決定。也就是說,你可以傳入任意多的,以分號分隔的字符串(包括空的列表)。這些字符串會被存在一個名為strings 的參數(shù)中。在這個方法里面,strings 實際上是一個Array(數(shù)組)。

注意

當(dāng)在代碼里顯式地為變量指定類型信息時,類型注解應(yīng)該跟在變量名的冒號后面(也就是類Pascal 語法)。Scala 為什么不遵照J(rèn)ava 的慣例呢? 回想一下,類型信息在Scala 中經(jīng)常是被推斷出來的(不像Java),這意味著我們并不總是需要顯式的聲明類型。和Java 的類型習(xí)慣比較,item: type 模式在你忽略掉冒號和類型注解的時候,更容易被編譯器清楚地分析。

方法的返回類型在參數(shù)列表的***出現(xiàn)。在這個例子里,返回類型是Seq[String],Seq(sequence)是一種特殊的集合。它是參數(shù)化的類型(像Java 中的泛型),在這里String 是參數(shù)。注意,Scala 使用方括號[...] 來指定參數(shù)類型,而Java 使用尖括號<...>。

注意

Scala 允許在方法名中使用尖括號,比如命名“小于”方法為<,這很常見。所以,為了避免二義性,Scala 使用了方括號來聲明參數(shù)類型。它們不能被用于方法名。這就是為什么Scala 不允許像Java 那樣的使用尖括號的習(xí)慣。

upper 方法的主體跟在等于號“=”后面。為什么是一個等于號?為什么不像Java 一樣直接使用大括號{...} 呢?因為分號,函數(shù)返回類型,方法參數(shù)列表,甚至大括號都經(jīng)常會被省略,使用等于號可以避免幾種可能的二義性。使用等于號也提醒了我們,即使是函數(shù),在Scala 里面也是值。這和Scala 對函數(shù)是編程的支持是一致的。我們會在《第8章,Scala 函數(shù)式編程》里討論更多的細(xì)節(jié)。

函數(shù)的主體調(diào)用了strings 數(shù)組的map 方法,它接受一個字面函數(shù)(Function Literal)作為參數(shù)。字面函數(shù)也就是“匿名”函數(shù)。它們類似于其它語言中的Lambda 表達式,閉包,塊,或者過程。在Java 里,你可能會在這里使用一個匿名內(nèi)部類來實現(xiàn)一個接口(interface)定義的方法。

在這個例子里,我們傳入這樣的一個字面函數(shù)。

  1. (s:String) => s.toUpperCase() 

它接受一個單獨的名為s 的String 類型參數(shù). 函數(shù)的主體在“箭頭” => 的后面。它調(diào)用了s 的toUpperCase() 方法。調(diào)用的結(jié)果會被函數(shù)返回。在Scala 中,函數(shù)的***一個表達式就是返回值,盡管你也可以在其它地方使用return 語句。return 關(guān)鍵字在這里是可選的,而且很少被用到,除非在一段代碼中間返回(比如在一個if 語句塊中)。

注意

***一個表達式的值是默認(rèn)的返回值。不需要顯式的return。

繼續(xù),map 把strings 里面的每一個String 傳遞給字面函數(shù),從而用這些返回值創(chuàng)建了一個新的集合。

要運行這些代碼,我們創(chuàng)建一個新的Upper 實例,然后把它賦值給一個名為up 的變量。和Java,C#,以及其它類似的語言一樣,語法new Upper 創(chuàng)建了一個新的實例。變量up 被val 關(guān)鍵字定義為一個只讀的值。

***,我們對一個字符串列表調(diào)用upper 方法,然后用Console.println(...) 方法打印出來。這和Java 的System.out.println(...) 等效。

實際上,我們可以更加簡化我們的代碼。來看下面這一段簡化版的腳本。

  1. // code-examples/IntroducingScala/upper2-script.scala  
  2.  
  3. object Upper {  
  4.   def upper(strings: String*) = strings.map(_.toUpperCase())  
  5. }  
  6. println(Upper.upper("A", "First", "Scala", "Program"))  

這段代碼做了一模一樣的事情,但是用了更少的字符。

在***行,Upper 被定義為一個object,也就是單體模式。實際上我們是定義了一個class,但是Scala 運行時僅會創(chuàng)建Upper 的一個實例。(比如,你就不能寫new Upper了。)Scala 的objects 被使用在其他語言需要“類級別”的成員的時候,比如Java 的statics (靜態(tài)成員)。我們實際上并不需要更多的實例,所以單體模式也不錯。

注意

Scala 為什么不支持statics?因為在Scala 中,所有的東西都是一個object,object 結(jié)構(gòu)使得這樣的政策保持了一致。Java 的static 方法和字段并不綁定到一個實際的實例。

注意這樣的代碼是完全線程安全的。我們沒有定義任何會引起線程安全問題的變量。我們使用的API 方法也是線程安全的。所以,我們不需要多個實例。單體模式工作的很好。

在第二行的upper 方法的實現(xiàn)也變簡單了。Scala 通??梢酝茢喑龇椒ǖ姆祷刂担ǖ欠椒▍?shù)的類型就不行了),所以我們不用顯式聲明。而且,因為在方法的主體中只有一個表達式,我們也省略了括號,把整個方法的定義放到一行中。方法主體前面的等于號告訴編譯器函數(shù)的主體從這里開始,就像我們看到的一樣。

我們也在字面函數(shù)里利用一些簡寫。之前我們像這樣寫一個函數(shù):

  1. (s:String) => s.toUpperCase() 

我們可以簡化成如下表達式:

  1. _.toUpperCase() 

因為map 接受一個參數(shù),即一個函數(shù),我們可以用 _ 占位符來替代有名參數(shù)。也就是說,_ 像是一個匿名變量,在調(diào)用 toUpperCase 之前每一個字符串都會被賦值給它。注意,String 類型是被推斷出來的。將來我們會看到,Scala 還會在某些上下文中充當(dāng)通配符。

你可以在一些更復(fù)雜的字面函數(shù)中使用這種簡化的語法,就像我們將在《第3章 - 要點詳解》中看到的那樣。

在***一行,我們使用了一個object 而不是一個class 來簡化代碼。我們只要在Upper object 上直接調(diào)用upper 方法,而不用new Upper 來創(chuàng)建一個新的實例。(注意,這樣的語法看起來很像在Java 類中調(diào)用一個靜態(tài)方法。

***,Scala 自動導(dǎo)入了許多用以輸入輸出的方法,比如println,所以我們不用寫成Console.println()。我們只使用println 本身就可以了。(參見《第7章 - Scala Obejct 系統(tǒng)》的“預(yù)定義Object ”章節(jié)來獲取更多有關(guān)自動導(dǎo)入類型和方法的信息。)

讓我們來做***一次重構(gòu);讓我們把這段腳本變成一個編譯好的命令行工具。

  1. // code-examples/IntroducingScala/upper3.scala  
  2. object Upper {  
  3.   def main(args: Array[String]) = {  
  4.     args.map(_.toUpperCase()).foreach(printf("%s ",_))  
  5.     println("")  
  6.   }  

現(xiàn)在upper 方法被重命名為main。因為Upper 是一個object,這個main 方法就像Java 類里的static main 方法一樣。這個Upper 程序的入口。

注意

在Scala,main 必須是一個object 的函數(shù)。(在Java,main 必須是一個類的靜態(tài)方法。)命令行參數(shù)會作為一個字符串?dāng)?shù)組被傳入應(yīng)用程序,比如 args: Array[String]。

main 方法的***行使用了和我們剛才產(chǎn)看過的map 方法一樣的簡寫。

  1. args.map(_.toUpperCase())... 

調(diào)用map 會返回一個新的集合。我們用foreach 來遍歷它。我們在傳給foreach 的這個字面函數(shù)中再一次使用了一個 _ 占位符。這樣,集合的每一個字符串會被作為printf 的參數(shù)傳入。

  1. ...foreach(printf("%s ",_)) 

更清楚地說明一下,這兩個“_”是完全相互獨立的。這個例子里的連鎖方法(Method Chaining)和簡寫字面函數(shù)需要花一些時間來習(xí)慣,但是一旦你熟悉了它們,他們用最少的臨時變量來產(chǎn)生可讀性很高的代碼。

main 的***一行在輸出中加入了一個換行。

在這次,你必須先用scalac 來把代碼編譯成JVM 可認(rèn)的.class 文件。 

scalac upper3.scala

你現(xiàn)在應(yīng)該有一個名為Upper.class 的文件,就像你剛編譯了一個Java 類一樣。

注意

你可能已經(jīng)注意到編譯器并沒有因為文件名為upper3.scala 而object 名為Upper 而抱怨。不像Java,這里文件名不用和公開域內(nèi)的類型名字一致。(我們會在《第5章 - Scala 基礎(chǔ)面向?qū)ο缶幊獭返?ldquo;可見性規(guī)則”章節(jié)來探索可見性規(guī)則。)實際上,和Java 不同,你可以在一個單獨文件中有很多公開類型。此外,文件的地址也不用和包的聲明一致。不過,如果你愿意,你可以依舊遵循Java 的規(guī)則。

現(xiàn)在,你可以傳入任意多個字符串來執(zhí)行這個命令了。比如:

  1. scala -cp . Upper Hello World! 

-cp 選項會把當(dāng)前目錄加入到“類路徑”的搜索中去。你會得到如下輸出:

  1. HELLO WORLD! 

這樣,我們已經(jīng)滿足了一本編程語言書籍必須以一個“hello world ”程序開始的基本要求。

#p#

初嘗并發(fā)

被Scala 吸引有很多原因。 其中一個就是Scala 庫的Actors API。它基于Erlang [Haller2007] 強大的Actors 并發(fā)模型建立。這里有一個例子來滿足你的好奇心。

在Actor 并發(fā)模型[Agha1987] 中, 被稱為執(zhí)行者(Actor) 的獨立軟件實體不會互相之間共享狀態(tài)信息. 相反, 它們通過交換消息來通信. 沒有了共享易變狀態(tài)的需要, 就更容易寫出健壯的并發(fā)應(yīng)用程序.

在這個例子里, 不同的圖形的實例被發(fā)送到執(zhí)行者(Actor )來進行繪畫和顯示. 想象這樣一個場景: 一個渲染集群在為動畫生成場景. 在場景渲染完成之后, 場景中的元圖形會被發(fā)送到一個執(zhí)行者中由顯示子系統(tǒng)處理.

我們從定義一系列的Shape (形狀) 類開始.

  1. // code-examples/IntroducingScala/shapes.scala  
  2. package shapes {  
  3.   class Point(val x: Double, val y: Double) {  
  4.     override def toString() = "Point(" + x + "," + y + ")"  
  5.   }  
  6.   abstract class Shape() {  
  7.     def draw(): Unit  
  8.   }  
  9.  class Circle(val center: Point, val radius: Double)   
  10.     extends Shape {  
  11.     def draw() = println("Circle.draw: " + this)  
  12.     override def toString() =   
  13.        "Circle(" + center + "," + radius + ")"  
  14.   }  
  15.   class Rectangle(val lowerLeft: Point, val height: Double, val width: Double)  
  16.         extends Shape {  
  17.     def draw() = println("Rectangle.draw: " + this)  
  18.     override def toString() =  
  19.       "Rectangle(" + lowerLeft + "," + height + "," + width + ")"  
  20.   }  
  21.   class Triangle(val point1: Point, val point2: Point, val point3: Point)  
  22.         extends Shape {  
  23.     def draw() = println("Triangle.draw: " + this)  
  24.     override def toString() =  
  25.       "Triangle(" + point1 + "," + point2 + "," + point3 + ")"  
  26.   }  

類Shape 的繼承結(jié)構(gòu)在shapes 包(package)中定義。你可以用Java 的語法定義包,但是Scala 也支持類似于C# 的名稱空間的語法,就是把整個聲明都包含在大括號的域中,就像這里所做的。Java 風(fēng)格的包聲明語法并不經(jīng)常用到,然而,它們都一樣精簡和可讀。

類Point(點)表示了在一個平面上的二位點。注意類名字后面的參數(shù)列表。它們是構(gòu)造函數(shù)的參數(shù)。在Scala 中,整個類的主體就是構(gòu)造函數(shù),所以你可以在類名字后面,類實體之前的主構(gòu)造函數(shù)里列出所有參數(shù)。(在《第5章 - Scala 的基本面向?qū)ο缶幊獭返?ldquo;Scala 的構(gòu)造函數(shù)”章節(jié)中,我們會看到如何定義輔助的構(gòu)造函數(shù)。)因為我們在每一個參數(shù)聲明前放置了val 關(guān)鍵字,它們會被自動地轉(zhuǎn)換為有同樣名字的只讀的字段,并且伴有同樣名字的公開讀取方法。也就是說,當(dāng)你初始化一個Point 的實例時,比如point, 你可以通過point.x 和point.y 來讀取字段。如果你希望有可變的字段,那么使用var 關(guān)鍵字。我們會在《第2章 - 打更少的字,做更多的事》的“變量聲明”章節(jié)來探索如何使用val 和var 關(guān)鍵字聲明變量。

Point 類的主體定義了一個方法,類似于Java 的toString 方法的重寫(或者C# 的ToString 方法)。主意,Scala 像C# 一樣,在重寫一個具體方法時需要顯式的override 關(guān)鍵字。不過和C# 不一樣的是,你不需要一個virtual (虛擬)關(guān)鍵字在原來的具體方法上。實際上,在Scala 中沒有virtual 關(guān)鍵字。像之前一樣,我們省略了toString 方法主體兩邊的大括號“{…}”,因為我們只有一個表達式。

Shape 是一個抽象類。Scala 中的抽象類和Java 以及C# 中的很像。我們不能實例化一個抽象類,即使它們的字段和方法都是具體的。

在這個例子里,Shape 聲明了一個抽象的draw (繪制)方法。我們說它抽象是因為它沒有方法主體。在方法上不用寫abstract (抽象)關(guān)鍵字。Scala 中的抽象方法就像Java 和C# 中的一樣。(參見《第6章 - Scala 高級面向?qū)ο缶幊獭返?ldquo;重寫Classes 和Traits 的成員”章節(jié)獲取更多細(xì)節(jié)。)

draw 方法返回Unit,這種類型和Java 這樣的C 后繼語言中的void 大體一致。(參見《第7章 - Scala Object 系統(tǒng)》的“Scala 類型組織”來獲取更多細(xì)節(jié)。)

Circle (圓)被聲明為Shape 的一個具體的子類。 它定義了draw 方法來簡單地打印一條消息到控制臺。Circle 也重寫了toString。

Rectangle 也是Shape 得一個具體子類,定義了draw 方法,重寫了toString。為了簡單起見,我們假設(shè)它不會相對X 或Y 軸旋轉(zhuǎn)。于是,我們所需要的就是一個點,左下角的點就可以,以及長方形的高度和寬度。

Triangle (三角形)遵循了同樣的模式。它獲取3個點作為它的構(gòu)造函數(shù)參數(shù)。

在Circle,Rectangle 和Triangle 的所有draw 方法里都用到了this。和Java,C# 一樣,this 是一個實例引用自己的方式。在這里的上下文中,this 在一個String 的鏈接表達式(使用加號)的右邊,this.toString 被隱式地調(diào)用了。

注意

當(dāng)然,在一個真正的程序中,你不會像這樣實現(xiàn)一個域模型里的drawing 方法,因為實現(xiàn)會依賴于操作系統(tǒng)平臺,繪圖API 等細(xì)節(jié)。我們會在《第4章 - Traits》里看到一個更好地設(shè)計方式。

既然我們已經(jīng)定義了我們的形狀類型,讓我們回過頭來看Actors。我們定義了一個Actor 來接受消息(需要繪制的Shape)。

  1. // code-examples/IntroducingScala/shapes-actor.scala  
  2. package shapes {  
  3.   import scala.actors._  
  4.   import scala.actors.Actor._  
  5.   object ShapeDrawingActor extends Actor {  
  6.     def act() {  
  7.       loop {  
  8.         receive {  
  9.           case s: Shape => s.draw()  
  10.           case "exit"   => println("exiting..."); exit  
  11.           case x: Any   => println("Error: Unknown message! " + x)  
  12.         }  
  13.       }  
  14.     }  
  15.   }  

Actor 被聲明為shapes 包的一部分。接著,我們有兩個import (導(dǎo)入)表達式。

***個import 表達式導(dǎo)入了所有在scala.actors 包里的類型。在Scala 中,下劃線_ 的用法和Java 中的星號* 的用法一致。

注意

因為* 是方法名允許的合法字符,它不能在import 被用作通配符。所以,_ 被保留來作為替代。

Actor 的所有方法和公開域內(nèi)的字段會被導(dǎo)入。Actor 類型中沒有靜態(tài)導(dǎo)入類型,雖然Java 中會。不過,它們會被導(dǎo)入為一個object,名字一樣為Actor。類和object 可以使用同樣的名字,就像我們會在《第6章 - Scala 高級面向?qū)ο缶幊獭返?ldquo;伴隨實體”章節(jié)中看到的那樣。

我們的Actor 類定義,ShapeDrawingActor,是繼承自Actor (類型,不是實體)的一個實體。它的act 方法被重寫來執(zhí)行Actor 的實際工作。因為act 是一個抽象方法,我們不需要顯式地用override 關(guān)鍵字來重寫。我們的Actor 會無限循環(huán)來等待進來的消息。

在每一次循環(huán)中,receive 方法會被調(diào)用。它會阻塞當(dāng)前線程直到一個新的消息到來。為什么在receive 后面的代碼被包含在大括號{}中而不是小括號()呢?我們會在后面學(xué)到,有些情況下這樣的替代是被允許的,而且十分有用(參見《第3章 - Scala 本質(zhì)》)。現(xiàn)在,我們需要知道的是,在括號中的表達式組成了一個字面函數(shù),并且傳遞給了receive。這個字面函數(shù)給消息做了一個模式匹配來決定它被如何處理。由于case 語句的存在,它看上去像Java 中的一個典型的switch 表達式,實際上它們的行為也很相像。

***個case 給消息做了一個類型比較。(在代碼中沒有為消息實體做顯式變量聲明;它是被推斷出來的。)如果消息是Shape 類型的,***個case 會被滿足。消息實體會被轉(zhuǎn)換成Shape 并且賦值給變量s,然后s 的draw 方法會被調(diào)用。

如果消息不是一個Shape,第二個case 會被嘗試。如果消息是字符串 exit ,Actor 會打印一條消息然后結(jié)束執(zhí)行。Actors 通常需要一個優(yōu)雅退出的方式。

***一個case 處理所有其它任何類型的消息實例,作用和default (默認(rèn))case 一樣。Actor 會報告一個錯誤然后丟棄這個消息。Any 是Scala 類型結(jié)構(gòu)中所有類型的父類型,就像Java 和其他類型語言中的Object 根類型一樣。所以,這個case 塊會匹配任何類型的消息。模式匹配是頭饑餓的怪獸,我們必須把這個case 塊放在***,這樣它才不會把我們需要的消息也都吃掉!

回想一樣我們在Shape 類里定義draw 為一個抽象方法,然后我們在具體的子類里實現(xiàn)它。所以,在***個case 塊中的代碼執(zhí)行了一個多態(tài)操作。

模式匹配 vs. 多態(tài)

模式匹配在函數(shù)式編程中扮演了中心角色, 就好像多態(tài)在面向?qū)ο缶幊讨邪缪葜行慕巧粯印:瘮?shù)式的模式匹配比絕大多數(shù)像Java 這樣的命令式語言中的switch/case 語句更加重要和成熟。我們會在《第8章 - Scala 函數(shù)式編程》了解更多Scala 對于模式匹配支持的細(xì)節(jié)。在我們的這個例子里,我們可以開始看到,函數(shù)式模式匹配和面向?qū)ο蠖鄳B(tài)調(diào)度的有力結(jié)合會給Scala 這樣的混合范式語言帶來巨大好處。

***,這里有一段腳本來使用ShapeDrawingActor。

  1. // code-examples/IntroducingScala/shapes-actor-script.scala  
  2. import shapes._  
  3. ShapeDrawingActor.start()  
  4. ShapeDrawingActor ! new Circle(new Point(0.0,0.0), 1.0)  
  5. ShapeDrawingActor ! new Rectangle(new Point(0.0,0.0), 2, 5)  
  6. ShapeDrawingActor ! new Triangle(new Point(0.0,0.0),  
  7.                                  new Point(1.0,0.0),  
  8.                                  new Point(0.0,1.0))  
  9. ShapeDrawingActor ! 3.14159  
  10. ShapeDrawingActor ! "exit" 

在shapes 包里的所有形狀類會被導(dǎo)入。

ShapeDrawingActor 會被啟動。默認(rèn)情況下,它會運行在它自己的線程中(也有另外的選擇,我們會在《第9章 - 使用Actor 的健壯的,可伸縮的并發(fā)編程》中討論),等待消息。

有5個消息通過使用語法 actor ! message 被送到Actor。***個消息發(fā)送了一個Circle 實例。Actor 會“畫”出這個圓。第二個消息發(fā)送了Rectangle 消息。Actor 會“畫”出這個長方形。第三個消息對一個三角形做了同樣的事情。第四個消息發(fā)送了一個約等于Pi 的Double (雙精度浮點數(shù))值。這對于Actor 來說是一個未知消息,所以它只是打印了一個錯誤消息。***一個消息發(fā)送了exit 字符串,它會導(dǎo)致Actor 退出。

要實驗這個Actor 例子,從編譯這兩個源文件開始。你可以從O'Reilly 下載網(wǎng)站獲取源代碼(參見前言中獲取代碼示例的部分來取得更多細(xì)節(jié)信息),或者你也可以自己創(chuàng)建它們。

使用下面的命令來編譯文件。

  1.   scalac shapes.scala shapes-actor.scala 

雖然源文件的名字和位置并不和文件內(nèi)容匹配,你會發(fā)現(xiàn)生成的class 文件被寫入到一個shape 文件夾內(nèi),每一個類都會有一個class 文件對應(yīng)。這些class 文件的名字和位置必須和JVM 的需求相吻合。

現(xiàn)在你可以運行這個腳本來看看Actor 的實際運行。

  1.   scala -cp . shapes-actor-script.scala 

你應(yīng)該可以看到如下輸出。

  1.   Circle.draw: Circle(Point(0.0,0.0),1.0)  
  2.   Rectangle.draw: Rectangle(Point(0.0,0.0),2.0,5.0)  
  3.   Triangle.draw: Triangle(Point(0.0,0.0),Point(1.0,0.0),Point(0.0,1.0))  
  4.   Error: Unknown message! 3.14159  
  5.   exiting... 

要知道更多關(guān)于Actor 的細(xì)節(jié),參加《第9章 - 使用Actor 的強壯的,可伸縮的并發(fā)編程》。

概括

我們通過Scala 的示例來讓你開始對Scala 有所了解,其中一個還給出了Scala Actors 庫的強大并發(fā)編程體驗。下面,我們會更深入Scala 語法,強調(diào)各種各樣快速完成大量任務(wù)的“鍵盤金融”方式。

【編輯推薦】

  1. 第二章《揭示Scala的本質(zhì)》 
  2. 第三章《更少的字更多的事》
  3. “Scala” 一個有趣的語言
  4. 51CTO專訪Scala創(chuàng)始人:Scala拒絕學(xué)術(shù)化
  5. 編程思想碰撞 Scala不是改良的Java
  6. Scala 2.8最終發(fā)布 全新功能值得期待
  7. 對象函數(shù)式編程 Scala簡史

 

 

責(zé)任編輯:佚名 來源: 51CTO
相關(guān)推薦

2010-09-14 15:34:41

Scala

2010-11-17 11:31:22

Scala基礎(chǔ)面向?qū)ο?/a>Scala

2023-10-14 17:21:53

Scala編程

2010-10-14 13:50:11

Scala

2010-09-14 14:28:58

Scala

2009-02-06 09:08:04

Scala函數(shù)語言輕量級

2020-12-29 06:44:18

GoScala編程語言

2009-07-08 12:43:59

Scala ServlScala語言

2012-11-20 10:20:57

Go

2009-07-21 10:04:57

Scala編程語言

2011-08-31 09:03:09

ScalaAndroid編程語言

2018-05-07 09:09:13

編程語言 C 語言Java

2020-10-31 17:33:18

Scala語言函數(shù)

2010-02-23 10:44:00

Python 編程語言

2009-09-09 10:50:55

Scala例子Scala與Java

2009-07-30 13:21:17

Scala入門Hello World

2009-07-28 08:28:15

2014-06-06 09:13:28

SwiftSwift編程

2019-03-29 15:20:48

區(qū)塊鏈編程語言開發(fā)者

2010-03-11 10:34:22

Scala
點贊
收藏

51CTO技術(shù)棧公眾號