欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Swift的函數(shù)式編程詳解

 更新時(shí)間:2015年01月12日 09:10:42   投稿:junjie  
這篇文章主要介紹了Swift的函數(shù)式編程詳解,本文講解了Swift概覽、Swift遞歸、Swift 的高階函數(shù)和閉包等內(nèi)容,需要的朋友可以參考下

Swift 相比原先的 Objective-C 最重要的優(yōu)點(diǎn)之一,就是對(duì)函數(shù)式編程提供了更好的支持。 Swift 提供了更多的語(yǔ)法和一些新特性來(lái)增強(qiáng)函數(shù)式編程的能力,本文就在這方面進(jìn)行一些討論。

Swift 概覽

對(duì)編程語(yǔ)言有了一些經(jīng)驗(yàn)的程序員,尤其是那些對(duì)多種不同類(lèi)型的編程語(yǔ)言都有經(jīng)驗(yàn)的開(kāi)發(fā)者, 在學(xué)習(xí)新的語(yǔ)言的時(shí)候更加得心應(yīng)手。原因在于編程語(yǔ)言本身也是有各種范式的, 把握住這些特點(diǎn)就可以比較容易的上手了。

在入手一門(mén)新的語(yǔ)言的時(shí)候,一般關(guān)注的內(nèi)容有:

1.原生數(shù)據(jù)結(jié)構(gòu)
2.運(yùn)算符
3.分支控制
4.如果是面向?qū)ο蟮木幊陶Z(yǔ)言,其面向?qū)ο蟮膶?shí)現(xiàn)是怎樣的
5.如果是函數(shù)式編程語(yǔ)言,其面向函數(shù)式編程的實(shí)現(xiàn)是怎樣的

通過(guò)這幾個(gè)點(diǎn),其實(shí)只要閱讀 Swift 文檔的第一章,你就可以對(duì)這個(gè)語(yǔ)言有一個(gè)大概的印象。 比如對(duì)于數(shù)據(jù)結(jié)構(gòu),Swift 和其他的編程語(yǔ)言大體一樣,有 Int, Float, Array, Dictionary 等, 運(yùn)算符也基本與 C 語(yǔ)言一致等。 本文主要集中于對(duì) Swift 函數(shù)式編程方面的特點(diǎn)進(jìn)行一些盤(pán)點(diǎn),因此在這里假設(shè)大家對(duì) Swift 的基本語(yǔ)法已經(jīng)有所了解。

對(duì)于一種編程范式,要掌握它也要抓住一些要點(diǎn)。對(duì)于支持函數(shù)式編程的語(yǔ)言,其一般的特點(diǎn)可能包含以下幾種:

1.支持遞歸
2.函數(shù)本身是語(yǔ)言 First Class 的組成要素,且支持高階函數(shù)和閉包
3.函數(shù)調(diào)用盡可能沒(méi)有副作用 (Side Effect) 的條件

接下來(lái)我們來(lái)逐個(gè)盤(pán)點(diǎn)這些內(nèi)容。

遞歸

Swift 是支持遞歸的,事實(shí)上現(xiàn)在不支持遞歸的編程語(yǔ)言已經(jīng)很難找到了。在 Swift 里寫(xiě)一個(gè)遞歸調(diào)用和其他編程語(yǔ)言并沒(méi)有什么區(qū)別:

復(fù)制代碼 代碼如下:

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

關(guān)于 Swift 的遞歸沒(méi)有什么好說(shuō)的。作為一個(gè)常識(shí),我們知道遞歸是需要消耗棧空間的。 在函數(shù)式編程語(yǔ)言中,遞歸是一個(gè)非常常用的方法,然而使用不慎很容易導(dǎo)致棧溢出的問(wèn)題。 如果將代碼改寫(xiě)為非遞歸實(shí)現(xiàn),又可能會(huì)導(dǎo)致代碼的可讀性變差,因此有一個(gè)技巧是使用“尾遞歸”, 然后讓編譯器來(lái)優(yōu)化代碼。

一個(gè) Common Lisp 的尾遞歸的例子是

復(fù)制代碼 代碼如下:

(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 代碼也改寫(xiě)成相同形式

復(fù)制代碼 代碼如下:

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 里觀察是否使用尾遞歸時(shí)的迭代結(jié)果變化。

值得注意的是,這里出現(xiàn)了一個(gè) Swift 的問(wèn)題。雖然 Swift 支持嵌套函數(shù),但是當(dāng)我們將fibiter 作為一個(gè)高階函數(shù)包含在fib函數(shù)之內(nèi)的時(shí)候卻發(fā)生了 EXC_BAD_ACCESS 報(bào)錯(cuò), 并不清楚這是語(yǔ)言限制還是 Bug。

Swift 的高階函數(shù)和閉包

在 Objective-C 時(shí)代,使用 block 來(lái)實(shí)現(xiàn)高階函數(shù)或者閉包已經(jīng)是非常成熟的技術(shù)了。 Swift 相比 Objective-C 的提高在于為函數(shù)式編程添加了諸多語(yǔ)法上的方便。

首先是高階函數(shù)的支持,可以在函數(shù)內(nèi)定義函數(shù),下面就是一個(gè)很簡(jiǎn)潔的例子。

復(fù)制代碼 代碼如下:

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 實(shí)現(xiàn)上述功能,可讀性就不會(huì)有這么好。而且 block 的語(yǔ)法本身也比較怪異, 之前沒(méi)少被人吐槽。Swift 從這個(gè)角度來(lái)看比較方便。事實(shí)上,在 Swift 里可以將函數(shù)當(dāng)做對(duì)象賦值, 這和很多函數(shù)式編程語(yǔ)言是一樣的。

作為一盤(pán)大雜燴,Swift 的函數(shù)系統(tǒng)也很有 JavaScript 的影子在里面。比如可以向下面這樣定義函數(shù):

復(fù)制代碼 代碼如下:

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

等號(hào)之后被賦予變量add的是一個(gè)閉包表達(dá)式,因此更準(zhǔn)確的說(shuō), 這是將一個(gè)閉包賦值給常量了。注意在閉包表達(dá)式中,in關(guān)鍵字之前是閉包的形式定義,之后是具體代碼實(shí)現(xiàn)。 Swift 中的閉包跟匿名函數(shù)沒(méi)有什么區(qū)別。 如果你將它賦值給對(duì)象,就跟 JavaScript 中相同的實(shí)踐是一樣的了。幸好 Swift 作為 C 系列的語(yǔ)言, 其分支語(yǔ)句 if 等本身是有作用域的,因此不會(huì)出現(xiàn)下列 JavaScript 的坑:

復(fù)制代碼 代碼如下:

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

Swift 的閉包表達(dá)式和函數(shù)都可以作為函數(shù)的參數(shù),從下面的代碼我們可以看出閉包和函數(shù)的一致性:

復(fù)制代碼 代碼如下:

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

類(lèi)似于 Ruby,Swift 作為函數(shù)參數(shù)的閉包做了一點(diǎn)語(yǔ)法糖。 在 Ruby 中使用 Block 的時(shí)候,我們可以這樣寫(xiě):

復(fù)制代碼 代碼如下:

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

在 Swift 當(dāng)中我們可以得到幾乎一樣的表達(dá)式。

復(fù)制代碼 代碼如下:

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

也就是說(shuō), 如果一個(gè)函數(shù)的最后一個(gè)參數(shù)是閉包,那么它在語(yǔ)法上可以放在函數(shù)調(diào)用的外面。 閉包還可以用$0、$1等分別來(lái)表示第 0、第 1 個(gè)參數(shù)等。 基本的運(yùn)算符也可以看做函數(shù)。 下面的幾種方式都可以實(shí)現(xiàn)逆序倒排的功能。

復(fù)制代碼 代碼如下:

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>總體來(lái)說(shuō),Swift 在添加方便函數(shù)操作、添加相關(guān)語(yǔ)法糖方面走的很遠(yuǎn),基本上整合了目前各種語(yǔ)言中比較方便的特性。 實(shí)用性較好。</p><p><strong>Side Effects</strong></p><p>在計(jì)算機(jī)科學(xué)中,函數(shù)副作用指當(dāng)調(diào)用函數(shù)時(shí),除了返回函數(shù)值之外,還對(duì)主調(diào)用函數(shù)產(chǎn)生附加的影響。例如修改全局變量 (函數(shù)外的變量) 或修改參數(shù) (<a href=" b = a
a += "world"
print a # hello, world
print b # hello,</pre><p>Swift 的數(shù)據(jù)結(jié)構(gòu)的 Persist 性質(zhì)跟 Python 有點(diǎn)類(lèi)似。需要注意的是,Swift 有變量和常量?jī)煞N概念, 變量使用var聲明,常量使用let聲明,使用var聲明的時(shí)候,Swift 中的字符串的行為跟 Python 相似, 因此修改字符串可以被理解為生成了一個(gè)新的字符串并修改了指針。同樣, 使用var聲明的數(shù)組和字典也都是可變的。</p><p>在 Swift 中使用let聲明的對(duì)象不能被賦值,基本數(shù)據(jù)結(jié)果也會(huì)變得不可變,但是情況更復(fù)雜一點(diǎn)。</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聲明的字典是完全不可變的,但是數(shù)組雖然不可以改變長(zhǎng)度, 卻可以改變數(shù)組元素的值!Swift 的文檔中指出這里其實(shí)是將 Array 理解為定長(zhǎng)數(shù)組從而方便編譯優(yōu)化, 來(lái)獲得更好的訪問(wèn)性能。</p><p>綜上所述,對(duì)象是否可變的關(guān)系其實(shí)略有復(fù)雜的,可以總結(jié)為:</p><ol class=" list-paddingleft-2"><li><p>使用var和let,Int和String類(lèi)型都是不可變的,但是var時(shí)可以對(duì)變量重新賦值</p></li><li><p>使用let聲明的常量不可以被重新賦值</p></li><li><p>使用let聲明的Dictionary是完全不可變的</p></li><li><p>使用let聲明的Array長(zhǎng)度不可變,但是可以修改元素的值</p></li><li><p>使用let聲明的類(lèi)對(duì)象是可變的</p></li></ol><p>綜上所述,即使是使用let聲明的對(duì)象也有可能可變,因此在多線程情況下就無(wú)法達(dá)到“無(wú)副作用”的要求了。</p><p>此外 Swift 的函數(shù)雖然沒(méi)有指針,但是仍通過(guò)參數(shù)來(lái)修改變量的。只要在函數(shù)的參數(shù)定義中加入inout關(guān)鍵字即可。 這個(gè)特性很有 C 的風(fēng)格。</p><p>個(gè)人覺(jué)得在支持通過(guò)元組來(lái)實(shí)現(xiàn)多返回值的情況下,這個(gè)特性不但顯得雞肋,也是一個(gè)導(dǎo)致程序產(chǎn)生“副作用”的特性。 Swift 支持這樣的特性,恐怕更多的是為了兼容 Objective-C 以及方便在兩個(gè)語(yǔ)言之間搭建 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 自帶的數(shù)據(jù)結(jié)構(gòu)并不能很好的實(shí)現(xiàn)“無(wú)副作用”的“純函數(shù)式”編程, 它并沒(méi)有比 Python、Ruby 這類(lèi)語(yǔ)言走的更遠(yuǎn)。幸好作為一種關(guān)注度很高的語(yǔ)言, 已經(jīng)有開(kāi)發(fā)者為其實(shí)現(xiàn)了一套完全滿足不可變要求的數(shù)據(jù)結(jié)構(gòu)和庫(kù):Swiftz。 堅(jiān)持使用let和 Swiftz 提供的數(shù)據(jù)結(jié)構(gòu)來(lái)操作,就可以實(shí)現(xiàn)“純函數(shù)式”編程。</p><p><strong>總結(jié)</strong></p><p>在我看來(lái),Swift 雖然實(shí)現(xiàn)了很多其他語(yǔ)言的亮點(diǎn)特性,但是總體實(shí)現(xiàn)來(lái)說(shuō)并不是很整齊。 它在函數(shù)式編程方面添加了很多特性,但在控制副作用方面僅能達(dá)到平均水準(zhǔn)。 有些特性看起來(lái)像是為了兼容原來(lái)的 Objective-C 才加入的。</p><p>Swift 寫(xiě)起來(lái)相對(duì)比 Objective-C 更方便一點(diǎn),脫離 Xcode 這樣的 IDE 來(lái)寫(xiě)也是應(yīng)該是可以的。 目前 Swift 只支持集中少量的原生數(shù)據(jù)結(jié)構(gòu)而沒(méi)有標(biāo)準(zhǔn)庫(kù),更不具備跨平臺(tái)特性,這是一個(gè)缺點(diǎn)。 在仔細(xì)閱讀了文檔之后發(fā)現(xiàn) Swift 本身的語(yǔ)法細(xì)節(jié)還是很多的,就比如switch分置語(yǔ)句的用法就有很多內(nèi)容。 入門(mén)學(xué)習(xí)的容易程度并沒(méi)有原來(lái)想象的那么好。我個(gè)人并不覺(jué)得這門(mén)語(yǔ)言會(huì)對(duì)其他平臺(tái)的開(kāi)發(fā)者有很大吸引力。</p><p>Swift 是一門(mén)很強(qiáng)大的語(yǔ)言,在其穩(wěn)定版本發(fā)布之后我認(rèn)為我會(huì)從 Objective-C 轉(zhuǎn)向 Swift 來(lái)進(jìn)行編程, 它在未來(lái)很可能成為 iOS 和 Mac 開(kāi)發(fā)的首選。</p>
            </b}>

相關(guān)文章

  • Swift實(shí)現(xiàn)“或”操作符的3種方法示例

    Swift實(shí)現(xiàn)“或”操作符的3種方法示例

    這篇文章主要給大家介紹了關(guān)于Swift實(shí)現(xiàn)“或”操作符的3種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Swift自定義UITableViewCell背景色

    Swift自定義UITableViewCell背景色

    這篇文章主要為大家詳細(xì)介紹了Swift自定義UITableViewCell背景色,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Swift中優(yōu)雅處理閉包導(dǎo)致的循環(huán)引用詳解

    Swift中優(yōu)雅處理閉包導(dǎo)致的循環(huán)引用詳解

    這篇文章主要給大家介紹了關(guān)于Swift中優(yōu)雅的處理閉包導(dǎo)致的循環(huán)引用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Swift具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Swift實(shí)現(xiàn)無(wú)限輪播效果

    Swift實(shí)現(xiàn)無(wú)限輪播效果

    這篇文章主要為大家詳細(xì)介紹了Swift無(wú)限輪播效果實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • swift學(xué)習(xí)文檔(筆記)

    swift學(xué)習(xí)文檔(筆記)

    這篇文章主要介紹了學(xué)習(xí)swift的筆記,swift最近也比較熱,需要的朋友可以參考下
    2014-09-09
  • Swift開(kāi)發(fā)中switch語(yǔ)句值綁定模式

    Swift開(kāi)發(fā)中switch語(yǔ)句值綁定模式

    本文給大家分享Swift開(kāi)發(fā)中switch語(yǔ)句值綁定模式,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下
    2016-12-12
  • swift 字符串String的使用方法

    swift 字符串String的使用方法

    這篇文章主要介紹了swift 字符串String的使用方法的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • 如何快速用上Swift靜態(tài)庫(kù)詳解

    如何快速用上Swift靜態(tài)庫(kù)詳解

    這篇文章主要給大家介紹了關(guān)于如何快速用上Swift靜態(tài)庫(kù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • Swift利用純代碼實(shí)現(xiàn)時(shí)鐘效果實(shí)例代碼

    Swift利用純代碼實(shí)現(xiàn)時(shí)鐘效果實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于Swift利用純代碼實(shí)現(xiàn)時(shí)鐘效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用swift具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • Swift NavigationBar隱藏后的右滑手勢(shì)效果

    Swift NavigationBar隱藏后的右滑手勢(shì)效果

    這篇文章主要為大家詳細(xì)介紹了Swift NavigationBar隱藏后的右滑手勢(shì)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評(píng)論