Swift 中的高階函式和函式巢狀

2022-05-05 01:51:11 字數 3854 閱讀 9783

在swift中,函式可做為「一等公民」的存在,也就意味著,我們可以和使用int以及string一樣,將函式當做 引數、值、型別來使用。

其中,將函式當作乙個引數和值來使用可見下:

typealias  addtwoints = (int,int)->(int)  

var functype =addtwoints.self

func aaddb(a:int,b:int) ->int

func addfunc(_ add:addtwoints,_ a:int,_ b:int) ->int

//呼叫

self.addfunc(aaddb,

5, 6) // print --> 11

呼叫函式 「self.addfunc(aaddb, 5, 6)」 時候,aaddb就是乙個典型的「值」, 儘管它實際上是乙個函式。 與此同時, 它還做為addfunc的引數來使用。

雖然這看起來多此一舉,但實際這恰恰體現了高階函式的特點,犧牲一點點**的簡短,將重點體現在邏輯的清晰上。

我更喜歡叫下面的這個函式為高階函式:

var names:[string] = ["

61","

95","

8","

248","

42"] //

乙個包含字串的陣列

names = names.sorted

print(names) ----->["248", "42", "61", "8", "95"]

這是乙個排序函式。不要在意結果並沒有按照數字的大小排序,那是因為這是字串排序,規則將按照首個字母的asc值進行比較。

先看看這個函式的原型:

public func sorted(by areinincreasingorder: (element, element) -> bool) -> [element]

這個函式顯然是將乙個(element, element) -> bool型別的函式做為他的引數

一眼看過去,並不是那麼好理解,來看下其內部的實現大概是這樣的: 

extension array

swap(&tamper, &next)

swap(&self[n], &self[i])}}

return

newstring

}}

呼叫: 

names = ["

61","

95","

8","

248","42"

] names = names.mysorted

print(names) ----->["248", "42", "61", "8", "95"]

這裡為了簡便, 直接將element替換成了string,針對string 型別來說,這個函式的功能和系統的sotred的功能是一樣的。 如果需要支援更多的型別,可能要使用到泛型,甚至是where的可選繫結。其實系統的排序已經實現可選繫結式的排序了:過載了sorted函式,根據element的不同型別,推斷是否需要進行可選繫結動作。

通過這個例子,可以看到,所謂的高階函式,其實就是將乙個函式做為另乙個函式的引數的語法。這個語法的基礎是swift中的特性:函式的一等公民性質。

我們可以通過這種型別的語法,將類似的函式的內部**實現隱藏,只根據引數函式的值定義如何執行內部**。這中方式實現的**的靈活度將大大的提高。這為在swift 中寫出使用乙個函式替代多個同質化的函式提供了一種手段。 當然,做到這種效果可能還需要使用泛型程式設計。

大部分情況下,遇到的所有功能都是全域性函式,它們在全域性範圍內定義。如果在函式區域性定義乙個函式,則稱為巢狀函式。

預設情況下,巢狀函式從外部世界隱藏,但在區域性仍然可以正常低調用。乙個閉包的函式也可以返回乙個巢狀函式,以允許在其他範圍內使用巢狀函式。

func choosestepfunction(backward: bool) -> (int) ->int      //巢狀函式 1

func stepbackward(input: int) -> int //巢狀函式 2

return backward ?stepbackward : stepforward //返回乙個函式

}

呼叫:

var currentvalue = -4

let movenearertozero = choosestepfunction(backward: currentvalue > 0)//

movenearertozero now refers to the nested stepforward() function

while currentvalue != 0

print(

"zero!

")// zero!

巢狀函式的本質是返回乙個函式,之前所說的將函式當作引數基於同乙個特性 -- 函式是swift的 一等公民。

同樣的道理,乙個基本型別的既然能夠做為區域性的變數來存在,函式為什麼不行呢? 當然可以。這就是區域性函式的由來,看來還是基於一等公民的身份啊。 函式巢狀將遵守與基本型別一樣的原則,區域性的函式,職能夠在區域性去訪問,在外部是沒有效果的。

如果我們將巢狀的函式匿名的話,也即是我們下面的這種形式:

typealias  adds = (int)->(int)  func add(_ c:int) ->adds 

}

呼叫:

let addstart = self.add(0

)let addtwo = addstart(2

)let addfive = addstart(5

)print(addtwo) -----> 2

print(addfive) -----> 5

在add函式中,定義了乙個起始的數值: 0,返回乙個adds型別的函式。 之後我們可以通過給adds型別的例項 addtwo和addfive傳遞相應的引數即可實現多個函式的套用。 

比如,如果我們在做乙個以乙個起始值做為加減的時候,這中用法就靈活很多,比如,如果我需要以 10做為初始值:

let add = self.add(10

)let addtwo = add(2

)let addfive = add(5

)print(addtwo) ==> 12

print(addfive) --> 15

add已經是另乙個函式了。

而實際上,這就函式巢狀的另一種使用,這有很多的叫法 ,我更願意叫它 -- 柯里化。

在電腦科學中,柯里化(currying)是把接受多個引數的函式變換成接受乙個單一引數(最初函式的第乙個引數)的函式,並且返回接受餘下的引數且返回結果的新函式的技術。這個技術由 christopher strachey 以邏輯學家 haskell curry 命名的,儘管它是 moses schnfinkel 和 gottlob frege 發明的。

在一般函式中,並不能輕易做到柯里化,可能需要借助其他的方案,比如,將多個引數使用替換成乙個struct或者class。

然而高階函式和巢狀函式卻可以很輕易的做到,並保證**的邏輯清晰。然而為什麼要使用柯里化,可以閱讀這個文章。 私人覺得,柯里化的優勢是去同質化的** 以及 注重函式的實現減少引數的干擾,簡潔提公升邏輯。上面的例子剛好解釋了柯里化的使用。

Swift語法 高階函式

高階函式map,flatmap,reduce,filter可以簡化 量,能用就用。1 map函式,是集合和string類的例項方法,作用是遍歷時修改item map並不會修改例項值,而且新建乙個拷貝。摘自官方文件 let cast vivien marlon kim karl let lowerca...

Swift 中的函式(下)

學習來自 極客學院 swift中的函式 工具 xcode6.4 直接上基礎的示例 多敲多體會就會有收穫 百看不如一敲,一敲就會 1 import foundation23 巢狀函式 4 func getmathfunc type string int int 8 func cube num int ...

Scala高階 匿名函式和高階函式

scala版本 2.10.5 一 函式是第一等公民 1 把函式作為實參傳遞給另外乙個函式。2 把函式作為返回值。3 把函式賦值給變數。4 把函式儲存在資料結構裡。在scala中,函式就像普通變數一樣,同樣也具有函式的型別。二 函式型別 1 定義 在scala語言中,函式型別的格式為a b,表示乙個接...