scala入門之識別函數式風格

scala容許指令式的編程風格,可是鼓勵採用函數式的風格。若是你是從指令式的背景轉到scala來的-----例如,若是你是Java程序員------那麼學習scala將面對的主要挑戰就是理解怎樣用函數式的風格編程。咱們的首要工做是識別這兩種風格在代碼上的差別。大體能夠說,若是代碼包含了任何 var 變量,那它可能就是指令式的風格若是代碼根本就沒有 var ------就是說僅僅包含 val ------那它或許是函數式的風格。所以向函數式風格轉變的方式之一,就是嘗試不用任何 var 編程。
若是你來自於指令式的語言環境,如:Java、C++、或者C#,你或許認爲 var 是很正統的而 val 比較特殊。相反,若是你來自於函數式語言環境,如:Haskell、OCamel或Erlang,或許你會認爲 val 很正常而對 var 就有一種抵觸情緒了。然而在scala看來,val 和 var 只不過是工具箱裏兩種不一樣的工具。它們都頗有用,沒有一個天性邪惡。scala鼓勵你學習 val ,但最終作到「物盡其用」的原則。
指令式風格的例子:程序員

def printArgs(args:Array[String]):Unit = { 
    var i = 0
    while(i < args.length){ 
        println(args(i)) 
        i += 1
    } 
}

你能夠經過去掉 var 的辦法把這個代碼變得更函數式風格,如例:編程

def printArgs(args:Array[String]):Unit = { 
    for(arg <- args) 
        println(arg) 
}

或者:數組

def printArgs(args:Array[String]):Unit = { 
    args.foreach(println) 
}

這個例子說明了減小使用 var 的一個好處。重構後(更函數式)的代碼比原來(更指令式)的代碼更簡潔、明白,也更少有機會犯錯。scala鼓勵函數式風格的緣由,實際上也就是由於函數式風格能夠幫助你寫出更易讀懂,一樣也是更不易犯錯的代碼。
固然,這段代碼仍有修改的餘地。重構後的printArgs方法並非純函數式的,由於它有反作用(反作用?計算並返回結果以外的其它行爲??)------本例中的反作用就是打印到標準輸出流。識別函數是否有反作用的地方就在於其結果類型是否爲Unit。若是某個函數不返回任何有用的值,也就是說若是返回類型爲Unit,那麼這個函數惟一能產生的做用就只能是完成某種反作用。而函數風格的方式應該是定義對需打印的arg進行格式化的方法,不過僅返回格式化以後的字符串,如例:函數

def formatArgs(args:Array[String]) = args.mkString(「\n」);

如今纔是真正函數式風格的了:徹底沒有反作用或 var 的 mkString方法,能在任何可枚舉的集合類型(包括數組,列表,集和映射)上調用,返回由每一個數組元素調用mkString,並把傳入字符串作分隔符組成的字符串。固然,這個函數並不像printArgs方法那樣可以實際完成打印輸出,但能夠簡單地把它的結果傳遞給println來實現:工具

println(formatArgs(args));

每一個有用的程序都會有某種形式的反作用,不然就不可能向程序以外提供什麼有價值的東西。咱們提倡無反作用的方法是爲了鼓勵你儘可能設計出沒有反作用代碼的程序。這種方式的好處之一是能夠有助於你的程序更容易測試。舉例來講,要測試前面給出的任何一個有反作用的printArgs方法,你將須要重定義println,捕獲傳遞給它的輸出,再檢查結果。相反,對於formatArgs來講你能夠直接檢查它的返回結果:學習

val res = formatArgs(Array(「zero」,「one」,「two」);
assert(res == 「zero\none\ntwo」);

不過仍是要牢記:無論是var仍是反作用都不是天生邪惡的。Scala不是隻能使用函數式風格編程的純函數式語言。它是這兩種風格的混合式語言。甚至有時你會發現指令式風格能更有效地解決手中的問題,那就使用指令式風格,別猶豫
測試

相關文章
相關標籤/搜索