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

Scala如何改變了我的編程風(fēng)格:從命令式到函數(shù)式

原創(chuàng)
開發(fā) 后端
有時候?qū)W習(xí)一門新的編程語言,也會影響到你在其他語言中的編碼方式。在這篇隨筆中,Bill Venners與我們一起分享了學(xué)習(xí)Scala是如何影響到他的編程風(fēng)格的。

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

【51CTO快譯】編者前言:這篇文章最初寫于2008年底,作者Bill Venners一方面是美國著名開發(fā)網(wǎng)站Artima的總編,另一方面也是一位十分關(guān)注Scala語言的Java程序員。在這幾個月間的Scala創(chuàng)始人Martin Odersky訪談系列中,與Martin對話的正是Bill Venners。這篇文章雖然已經(jīng)完成了半年有余,但對于還不很熟悉Scala語言的Java程序員而言,仍然是一篇非常實用的Scala語言簡介。以下是譯文:

每次我學(xué)習(xí)一門新的語言,我都會學(xué)到某些編程方面的東西。比如說,當(dāng)我以一個C++程序員的身份學(xué)習(xí)Java的時候,Java的接口構(gòu)造教會我來自純粹的抽象基類的多重繼承的價值。盡管在C++里面這種編程風(fēng)格是有可能的,但在我使用C++的日子里,我卻沒有考慮用這種方式進行多重繼承,而我在C++設(shè)計中也不怎么使用抽象基類。然而,一旦我開始進行Java編程,我就開始一直使用這種風(fēng)格了。學(xué)習(xí)Java—尤其是它的接口構(gòu)造改變了我OO設(shè)計的方法。

51CTO編輯推薦:充分利用面向?qū)ο笳Z言的接口特性 | 面向?qū)ο蟮乃季S過程

我學(xué)習(xí)Scala編程的時候也發(fā)生了類似的情況。在過去的兩年里,我有相當(dāng)多的時間是用Scala工作的,ScalaJava平臺上的一種新的靜態(tài)類型語言,它融合了面向?qū)ο缶幊毯秃瘮?shù)型程序設(shè)計的概念。Scala能讓我寫出幾乎跟RubyPython一樣簡潔的代碼。在Scala我可以跟在Java里面一樣方便地調(diào)用Java庫,包括我已有的Java庫??紤]到Scala是靜態(tài)類型的,我可以享受到諸多靜態(tài)類型的好處,諸如將文檔作為類型,IDE代碼自動完成,動態(tài)代碼重構(gòu)(deterministic refactoring)以及執(zhí)行速度等(Scala程序的執(zhí)行速度跟Java的一樣快)。但Scala還讓我以簡潔和類型安全的方式獲得某些通常是動態(tài)語言的好處,例如在已有類上增加新方法的能力,或者將類型傳遞給沒有共同繼承關(guān)系的方法。

Scala是怎樣改變了我對編程的看法的呢?一句話:我學(xué)會了欣賞函數(shù)化的風(fēng)格。函數(shù)化的編程風(fēng)格強調(diào)不可變對象、變量可被初始化但不能重新賦值(Java中的最終變量)、數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換,以及方法和控制的構(gòu)造,最終產(chǎn)生一個沒有副作用的結(jié)果。這個領(lǐng)域的另一端是命令式的風(fēng)格,以可變對象、變量可被重新賦值(Java里的正常變量)、在數(shù)據(jù)結(jié)構(gòu)中索引、以及帶副作用的方法和控制構(gòu)造為特征。

盡管Scala經(jīng)常被吹捧為函數(shù)型編程語言,當(dāng)它并不僅僅是函數(shù)型的。Scala同時支持函數(shù)式和命令式兩種風(fēng)格。如果你自己選擇要這么做的話,你可以以Java的編程方式進行Scala編程,那種風(fēng)格主要是命令式的。這樣有助于Scala的學(xué)習(xí)曲線變緩,但隨著對Scala越來越熟悉,你就會發(fā)現(xiàn)自己會更喜歡函數(shù)式的。我就是這樣。為什么?因為我發(fā)現(xiàn)函數(shù)型風(fēng)格往往要比命令式風(fēng)格的代碼更簡潔,且更不易出錯。函數(shù)式風(fēng)格的代碼通常層次更高,這使得它編寫起來更快,閱讀也更為容易。舉個例子,看看下面這段確定一個字符串是否包含大寫字符的Java代碼。

boolean nameHasUpperCase = false; // 這是Java

for (int i = 0; i < name.length(); ++i) {

    if (Character.isUpperCase(name.charAt(i))) {

        nameHasUpperCase = true;

        break;

    } 

}

這里的命令式風(fēng)格是很明顯的,因為nameHasUpperCase變量被重新賦值會給loop循環(huán)帶來副作用,loop是通過字符串中的字母索引進行迭代的。在Java你還可以以更為簡潔的方式得到相同的結(jié)果,像下面這樣:

boolean nameHasUpperCase = !name.toLowerCase().equals(name);

這一行Java代碼展現(xiàn)出一種更為函數(shù)化的風(fēng)格,因為它轉(zhuǎn)換不可變數(shù)據(jù):name這個字符串被轉(zhuǎn)換為另外一個全部字母都是小寫的字符串,然后值被轉(zhuǎn)換為布爾結(jié)果。此外,nameHasUpperCase這個變量被初始化了,但僅限于這一小塊代碼里,而沒有被重新賦值。如果該變量為最終值的話,它的函數(shù)化就會更為清晰。

Scala里面,你可以寫出跟以上兩個例子類似的代碼,不過更為理想的編寫方式是像下面這樣的:

val nameHasUpperCase = name.exists(_.isUpperCase)

nameHasUpperCase變量被定義為 val,即可被初始化但不能被重新賦值的變量(類似于Java里面的最終變量)。甚至于盡管本例中并無顯式的類型標(biāo)注,Scala的類型推斷機制也會給nameHasUpperCase賦予Boolean類型。exists 方法在對象集合中迭代,并依次將每個元素傳遞給函數(shù)對象。在這里, name字符串被視為字符集合,因此exists會把字符串的每一個字符都傳遞給該函數(shù)。_.isUpperCase的語法是Scala里的一種函數(shù)顯式聲明(function literal),是一種編寫少量代碼就可以到處傳遞和調(diào)用的速寫方式。下劃線代表該函數(shù)的唯一參數(shù)。因此你可以把下劃線視為每次該函數(shù)被調(diào)用時待填的空白。如果exists 方法發(fā)現(xiàn)該函數(shù)因被傳遞的字符中的其中一個而返回true—比如說,其中一個字符是大寫的而返回true。否則就返回false。

盡管最后的這個單行代碼對于某些不熟悉Scala的人來說像是天書,只要你了解了Scala,你就能一眼看出代碼的目的。相反,其他的兩個版本卻要費上一點功夫去研究一下。另外需要注意的一點不同是命令式例子中潛在的偏移錯誤,因為你必須顯式地指出迭代的上標(biāo)。在函數(shù)化的版本里這種錯誤不會產(chǎn)生,在這種方式下,函數(shù)化版本相對而言不易出錯。

最后,我想指出的是我轉(zhuǎn)向Scala的時候并沒有“徹底函數(shù)化”。盡管我已經(jīng)發(fā)現(xiàn)通常大部分情況下函數(shù)化風(fēng)格的代碼來得更為簡潔、明晰,更不易出錯,我還發(fā)現(xiàn)有時候命令式風(fēng)格也可帶來更為清晰和簡潔的代碼。在那種情況下,我就會使用命令式的。Scala允許我方便地應(yīng)用函數(shù)式和命令式的風(fēng)格,結(jié)合使用此二者,我就能找到寫出清晰代碼的最佳方式。

#p#

函數(shù)式編程和命令式編程簡介

什么是函數(shù)式編程?(參考資料:《征服RIA:基于JavaScript的Web客戶端開發(fā)》第8章JavaScript函數(shù)對象

在數(shù)學(xué)領(lǐng)域,函數(shù)是一種關(guān)系,這種關(guān)系使一個集合里的每一個元素對應(yīng)到另一個集合里的唯一元素。函數(shù)是將唯一的輸出值賦予每一輸入的"法則"。這一"法則"可以用函數(shù)表達(dá)式、數(shù)學(xué)關(guān)系,或者一個將輸入值與輸出值對應(yīng)列出的簡單表格來表示。函數(shù)最重要的性質(zhì)是其決定性,即同一輸入總是對應(yīng)同一輸出(注意,反之未必成立)。從這種視角,可以將函數(shù)看做"機器"或者"黑盒",它將有效的輸入值變換為唯一的輸出值。通常將輸入值稱做函數(shù)的參數(shù),將輸出值稱做函數(shù)的值。

《Why Functional Programming Matters》的作者John Hughes 說明了模塊化是成功編程的關(guān)鍵,而函數(shù)編程可以極大地改進模塊化。在函數(shù)編程中,編程人員有一個天然框架用來開發(fā)更精練的、更小的、更簡單的和更一般化的模塊,然后將它們組合在一起。函數(shù)式編程的基本特點是:

豐富的數(shù)據(jù)類型;

函數(shù)是運算元;

在函數(shù)內(nèi)保存數(shù)據(jù);

函數(shù)內(nèi)的運算對函數(shù)外無副作用。

函數(shù)式編程只描述在程序輸入上執(zhí)行的操作,不必使用臨時變量保存中間結(jié)果。重點是捕捉"是什么以及為什么",而不是"如何做"。與將重點放在執(zhí)行連續(xù)命令上的過程性編程相比,函數(shù)式編程的重點是函數(shù)的定義而不是狀態(tài)機(State Machine)的實現(xiàn)。是一種強調(diào)表達(dá)式的計算而非命令的執(zhí)行的一種編程風(fēng)格。表達(dá)式是用函數(shù)結(jié)合基本值構(gòu)成的,它類似于用參數(shù)調(diào)用函數(shù)(函數(shù)式的優(yōu)美的說明可見《Functional Programming For The Rest of Us》)。

什么是命令式編程?(參考資料:維基百科)

命令式編程,是種描述電腦所需作出的行為的編程典范。幾乎所有電腦的硬體工作都是命令式的;幾乎所有電腦的硬體都是設(shè)計來執(zhí)行機器碼,使用命令式的風(fēng)格來寫的。較高階的命令式編程語言使用變數(shù)和更復(fù)雜的語句,但仍依從相同的典范。食譜和行動清單,雖非電腦程式,但與命令式編程有相似的風(fēng)格:每步都是指令,有形的世界控制情況。因為命令式編程的基礎(chǔ)觀念,不但概念上比較熟悉,而且較容易具體表現(xiàn)于硬體,所以大部分的編程語言都是命令式的。

原文:How Scala Changed My Programming Style  作者:Bill Venners

【相關(guān)閱讀】

  1. Scala的類型系統(tǒng) 比Java更靈活
  2. Java程序員,你為什么要關(guān)注Scala
  3. Scala創(chuàng)始人:創(chuàng)造比Java更好的語言
  4. Java以外的選擇 Scala編程語言簡介
  5. Java之外,選擇Scala還是Groovy?
責(zé)任編輯:yangsai 來源: 51CTO.com
相關(guān)推薦

2019-09-09 11:40:18

編程函數(shù)開發(fā)

2009-07-21 17:16:34

Scala函數(shù)式指令式

2009-07-09 00:25:00

Scala函數(shù)式

2009-06-22 14:59:51

AOP實現(xiàn)原理聲明式編程命令式編程

2010-03-11 10:34:22

Scala

2017-03-22 11:22:04

JavaScript函數(shù)式編程

2010-01-28 14:51:24

Scala后函數(shù)式

2009-07-08 16:10:24

Scala簡介面向?qū)ο?/a>函數(shù)式

2009-09-27 15:23:00

Scala講座函數(shù)式編程Scala

2011-08-24 09:13:40

編程

2013-06-27 09:31:37

聲明式編程命令式編程編程

2009-12-11 10:44:00

Scala講座函數(shù) scala

2020-09-22 11:00:11

Java技術(shù)開發(fā)

2020-09-23 07:50:45

Java函數(shù)式編程

2013-09-09 09:41:34

2010-07-09 14:12:00

ScalaF#C#

2010-07-07 13:11:20

ScalaF#C#

2023-07-10 09:39:02

lambdaPython語言

2012-09-21 09:21:44

函數(shù)式編程函數(shù)式語言編程

2011-03-08 15:47:32

函數(shù)式編程
點贊
收藏

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