程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 更多關於編程 >> Swift的函數式編程詳解

Swift的函數式編程詳解

編輯:更多關於編程

Swift的函數式編程詳解。本站提示廣大學習愛好者:(Swift的函數式編程詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是Swift的函數式編程詳解正文


Swift 比擬本來的 Objective-C 最主要的長處之一,就是對函數式編程供給了更好的支撐。 Swift 供給了更多的語法和一些新特征來加強函數式編程的才能,本文就在這方面停止一些評論辯論。

Swift 概覽

對編程說話有了一些經歷的法式員,特別是那些對多種分歧類型的編程說話都有經歷的開辟者, 在進修新的說話的時刻加倍輕車熟路。緣由在於編程說話自己也是有各類范式的, 掌握住這些特色便可以比擬輕易的上手了。

在動手一門新的說話的時刻,普通存眷的內容有:

1.原生數據構造
2.運算符
3.分支掌握
4.假如是面向對象的編程說話,其面向對象的完成是如何的
5.假如是函數式編程說話,其面向函數式編程的完成是如何的

經由過程這幾個點,其實只需浏覽 Swift 文檔的第一章,你便可以對這個說話有一個年夜概的印象。 好比關於數據構造,Swift 和其他的編程說話年夜體一樣,有 Int, Float, Array, Dictionary 等, 運算符也根本與 C 說話分歧等。 本文重要集中於對 Swift 函數式編程方面的特色停止一些清點,是以在這裡假定年夜家對 Swift 的根本語法曾經有所懂得。

關於一種編程范式,要控制它也要捉住一些要點。關於支撐函數式編程的說話,其普通的特色能夠包括以下幾種:

1.支撐遞歸
2.函數自己是說話 First Class 的構成要素,且支撐高階函數和閉包
3.函數挪用盡量沒有反作用 (Side Effect) 的前提

接上去我們來逐一清點這些內容。

遞歸

Swift 是支撐遞歸的,現實上如今不支撐遞歸的編程說話曾經很難找到了。在 Swift 裡寫一個遞歸挪用和其他編程說話並沒有甚麼差別:


func fib(n: Int) -> Int {
  if n <= 1 {
    return 1
  }
  else {
    return fib(n-1) + fib(n-2)
  }
}
fib(6) // output 13

關於 Swift 的遞歸沒有甚麼好說的。作為一個知識,我們曉得遞歸是須要消費棧空間的。 在函數式編程說話中,遞歸是一個異常經常使用的辦法,但是應用失慎很輕易招致棧溢出的成績。 假如將代碼改寫為非遞歸完成,又能夠會招致代碼的可讀性變差,是以有一個技能是應用“尾遞歸”, 然後讓編譯器來優化代碼。

一個 Common Lisp 的尾遞歸的例子是


(defun fib(n)
    (fib-iter 1 0 n))
(defun fib-iter(a b count)
    (if (= count 0)
        b
        (fib-iter (+ a b) a (- count 1))))

我們可以把我們上述的 Swift 代碼也改寫成雷同情勢


func fibiter(a: Int, b: Int, count: Int) -> Int {
  if count==0 {
    return b
  }
  else {
    return fibiter(a + b, a, count-1)
  }
}
func fib(n: Int) -> Int {
  return fibiter(1, 1, n);
}

我們可以 Playground 裡不雅察能否應用尾遞歸時的迭代成果變更。

值得留意的是,這裡湧現了一個 Swift 的成績。固然 Swift 支撐嵌套函數,然則當我們將fibiter 作為一個高階函數包括在fib函數以內的時刻卻產生了 EXC_BAD_ACCESS 報錯, 其實不清晰這是說話限制照樣 Bug。

Swift 的高階函數和閉包

在 Objective-C 時期,應用 block 來完成高階函數或許閉包曾經長短常成熟的技巧了。 Swift 比擬 Objective-C 的進步在於為函數式編程添加了諸多語法上的便利。

起首是高階函數的支撐,可以在函數內界說函數,上面就是一個很簡練的例子。


func greetingGenerator(object:String) -> (greeting:String) -> String {
  func sayGreeting(greeting:String) -> String {
    return greeting + ", " + object
  }
  return sayGreeting
}
let sayToWorld = greetingGenerator("world")
sayToWorld(greeting: "Hello") // "Hello, World"
sayToWorld(greeting: " 你好 ") // " 你好, World"

假如應用 block 完成上述功效,可讀性就不會有這麼好。並且 block 的語法自己也比擬奇異, 之前沒少被人吐槽。Swift 從這個角度來看比擬便利。現實上,在 Swift 裡可以將函數當作對象賦值, 這和許多函數式編程說話是一樣的。

作為一盤年夜雜燴,Swift 的函數體系也很有 JavaScript 的影子在外面。好比可以向上面如許界說函數:


let add = {
  (a:Int, b:Int) -> Int in
  return a+b
}
add(1, 2) // 3

等號以後被付與變量add的是一個閉包表達式,是以更精確的說, 這是將一個閉包賦值給常量了。留意在閉包表達式中,in症結字之前是閉包的情勢界說,以後是詳細代碼完成。 Swift 中的閉包跟匿名函數沒有甚麼差別。 假如你將它賦值給對象,就跟 JavaScript 中雷同的理論是一樣的了。幸虧 Swift 作為 C 系列的說話, 其分支語句 if 等自己是有感化域的,是以不會湧現以下 JavaScript 的坑:


if (someNum>0) {
  function a(){ alert("one") };
}
else {
  function a(){ alert("two") };
}
a() // will always alert "two" in most of browsers

Swift 的閉包表達式和函數都可以作為函數的參數,從上面的代碼我們可以看出閉包和函數的分歧性:

func function() {
  println("this is a function")
}
let closure = {
  () -> () in
  println("this is a closure")
}
func run(somethingCanRun:()-> ()) {
  somethingCanRun()
}
run(function)
run(closure)

相似於 Ruby,Swift 作為函數參數的閉包做了一點語法糖。 在 Ruby 中應用 Block 的時刻,我們可以如許寫:


(1...5).map {|x| x*2} // => [2, 4, 6, 8]

在 Swift 傍邊我們可以獲得簡直一樣的表達式。


var a = Array(1..5).map {x in x*2}
// a = [2, 4, 6, 8]

也就是說, 假如一個函數的最初一個參數是閉包,那末它在語法上可以放在函數挪用的裡面。 閉包還可以用$0、$1等分離來表現第 0、第 1 個參數等。 根本的運算符也能夠看作函數。 上面的幾種方法都可以完成逆序倒排的功效。


let thingsToSort = Array(1..5)
var reversed1 = sort(thingsToSort) { a, b in a<b} var reversed2 =" sort(thingsToSort) { $0 < $1}" var reversed3 =" sort(thingsToSort, <) // operator as a function"  all the above are [5, 4, 3, 2, 1]<="" pre=""><p>整體來講,Swift 在添加便利函數操作、添加相干語法糖方面走的很遠,根本上整合了今朝各類說話中比擬便利的特征。 適用性較好。</p><p><strong>Side Effects</strong></p><p>在盤算機迷信中,函數反作用指當挪用函數時,除前往函數值以外,還對主挪用函數發生附加的影響。例如修正全局變量 (函數外的變量) 或修正參數 (<a href="http://en.wikipedia.org/wiki/Side_effect_%28computer_science%29" target="_blank">wiki</a>)。 函數反作用會給法式帶來一些不用要的費事。</p><p>為了削減函數反作用,許多函數式編程說話都力圖到達所謂的“純函數”。 純函數是指函數與外界交流數據的獨一渠道是參數和前往值, 而不會遭到函數的內部變量的攪擾。 乍看起來這仿佛跟閉包的概念相抵牾,由於閉包自己的一個主要特色就是可以拜訪到函數界說時的高低文情況。</p><p>現實上,為了在這類情形下支撐純函數,一些編程說話如 Clojure 等供給的數據構造都是弗成變 (或許說 Persist) 的。 是以其實也就沒有我們傳統意義上的所以為的“變量”的概念。好比說,在 Python 中,字符串str就是一類弗成變的數據構造。 你不克不及在本來的字符串長進行修正,每次想要停止相似的操作,其實都是生成了一個新的str對象。 但是 Python 中的鏈表構造則是可變的。且看上面的代碼,在 Python 中對a字符串停止修正其實不會影響b, 然則異樣的操作感化於鏈表就會發生紛歧樣的成果:</p><pre class="brush:js;toolbar:false">a = "hello, "
b = a
a += "world"
print a # hello, world
print b # hello,</pre><p>Swift 的數據構造的 Persist 性質跟 Python 有點相似。須要留意的是,Swift 有變量和常量兩種概念, 變量應用var聲明,常量應用let聲明,應用var聲明的時刻,Swift 中的字符串的行動跟 Python 類似, 是以修正字符串可以被懂得為生成了一個新的字符串並修正了指針。異樣, 應用var聲明的數組和字典也都是可變的。</p><p>在 Swift 中應用let聲明的對象不克不及被賦值,根本數據成果也會變得弗成變,然則情形更龐雜一點。</p><pre class="brush:js;toolbar:false">let aDict = ["k1":"v1"]
let anArray = [1, 2, 3, 4]
aDict["k1"] = "newVal" // !! will fail !!
anArray.append(5) // !! will fail !!
anArray[0] = 5 // anArray = [5, 2, 3, 4] now !</pre><p>從下面的代碼中可以看出,應用let聲明的字典是完整弗成變的,然則數組固然弗成以轉變長度, 卻可以轉變數組元素的值!Swift 的文檔中指出這裡實際上是將 Array 懂得為定長數組從而便利編譯優化, 來取得更好的拜訪機能。</p><p>綜上所述,對象能否可變的關系其實略有龐雜的,可以總結為:</p><ol class=" list-paddingleft-2"><li><p>應用var和let,Int和String類型都是弗成變的,然則var時可以對變量從新賦值</p></li><li><p>應用let聲明的常量弗成以被從新賦值</p></li><li><p>應用let聲明的Dictionary是完整弗成變的</p></li><li><p>應用let聲明的Array長度弗成變,然則可以修正元素的值</p></li><li><p>應用let聲明的類對象是可變的</p></li></ol><p>綜上所述,即便是應用let聲明的對象也有能夠可變,是以在多線程情形下就沒法到達“無反作用”的請求了。</p><p>另外 Swift 的函數固然沒有指針,然則仍經由過程參數來修正變量的。只需在函數的參數界說中參加inout症結字便可。 這個特征很有 C 的作風。</p><p>小我認為在支撐經由過程元組來完成多前往值的情形下,這個特征不只顯得雞肋,也是一個招致法式發生“反作用”的特征。 Swift 支撐如許的特征,生怕更多的是為了兼容 Objective-C 和便利在兩個說話之間搭建 Bridge。</p><pre class="brush:js;toolbar:false">func inc(inout a:Int) {
  a += 1
}
var num = 1
inc(&num) // num = 2 now!</pre><p>綜上所述,應用 Swift 自帶的數據構造其實不能很好的完成“無反作用”的“純函數式”編程, 它並沒有比 Python、Ruby 這類說話走的更遠。幸虧作為一種存眷度很高的說話, 曾經有開辟者為其完成了一套完整知足弗成變請求的數據構造和庫:Swiftz。 保持應用let和 Swiftz 供給的數據構造來操作,便可以完成“純函數式”編程。</p><p><strong>總結</strong></p><p>在我看來,Swift 固然完成了許多其他說話的亮點特征,然則整體完成來講其實不是很整潔。 它在函數式編程方面添加了許多特征,但在掌握反作用方面僅能到達均勻水准。 有些特征看起來像是為了兼容本來的 Objective-C 才參加的。</p><p>Swift 寫起來絕對比 Objective-C 更便利一點,離開 Xcode 如許的 IDE 來寫也是應當是可以的。 今朝 Swift 只支撐集中大批的原生數據構造而沒有尺度庫,更不具有跨平台特征,這是一個缺陷。 在細心浏覽了文檔以後發明 Swift 自己的語法細節照樣許多的,就好比switch分置語句的用法就有許多內容。 入門進修的輕易水平並沒有本來想象的那末好。我小我其實不認為這門說話會對其他平台的開辟者有很年夜吸引力。</p><p>Swift 是一門很壯大的說話,在其穩固版本宣布以後我以為我會從 Objective-C 轉向 Swift 來停止編程, 它在將來極可能成為 iOS 和 Mac 開辟的首選。</p>
            </b}>

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved