Swift譯:《Swift3中狀態(tài)化循環(huán)和隊(duì)列》

原文作者:Erica Sadun
原文鏈接:http://ericasadun.com
時(shí)間:2016年7月19日
譯者:與狼同行

最近幾天我從Swift-Ev看到一個(gè)十分有趣的請(qǐng)求捍歪。


某位來自Swift-Ev社區(qū)成員:當(dāng)我敲代碼的時(shí)候,我很多次都會(huì)遇到這樣一個(gè)情型,當(dāng)使用‘repeat...while’循環(huán)時(shí),循環(huán)條件依賴于那些在循環(huán)體中被聲明變量迂卢。

repeat {
    let success = doSomething()
} while !success

這個(gè)請(qǐng)求吸引我的地方是它既需要范圍內(nèi)可見的狀態(tài)(success)而且還需要這個(gè)控制語句的狀態(tài)(success)沒有在外部范圍內(nèi)被聲明段只。

不用擔(dān)心,其實(shí)這個(gè)機(jī)制已經(jīng)在Swift中存在,來看看Swift里新的sequence函數(shù)奢浑。Swift提供了2個(gè)種類,兩個(gè)方式都提供基于循環(huán)域來建立狀態(tài)。


1.public func sequence<T>(first: T, next: (T) -> T?) -> UnfoldSequence<T, (T?, Bool)>

譯者解讀:
該函數(shù)功能為返回從以first”作為開始元素到不斷被"next"先前元素所返回的結(jié)果的一個(gè)隊(duì)列。
例如:
// 我們可以來走一遍樹的元素,從一個(gè)節(jié)點(diǎn)到它的根元素
 for node in sequence(first: leaf, next: { $0.parent }) {
       node是葉子節(jié)點(diǎn), 然后是它的父節(jié)點(diǎn), 再然后是它的父節(jié)點(diǎn)的父節(jié)點(diǎn), etc.
}
public func sequence<T>(first: T, next: (T) -> T?) -> UnfoldFirstSequence<T> {
  // 源碼中其實(shí)調(diào)用了第二種函數(shù),可以看出隊(duì)列第一個(gè)first的元組是true,則直接輸出第一個(gè)first元素,然后接下來隊(duì)列中的元素都執(zhí)行next后返回結(jié)果,直到最后結(jié)果為nil
  return sequence(state: (first, true), next: { (state: inout (T?, Bool)) -> T? in
    switch state {
    case (let value, true):
      state.1 = false
      return value
    case (let value?, _):
      let nextValue = next(value)
      state.0 = nextValue
      return nextValue
    case (nil, _):
      return nil
    }
  })
}

2.public func sequence<T, State>(state: State, next: (inout State) -> T?) -> UnfoldSequence<T, State>

譯者解讀:
源碼為:
public func sequence<T, State>(state: State, next: (inout State) -> T?)
  -> UnfoldSequence<T, State> {
  return UnfoldSequence(_state: state, _next: next)
//這里調(diào)用了另外一個(gè)結(jié)構(gòu)體UnfoldSequence,名為展開隊(duì)列
}
public struct UnfoldSequence<Element, State> : Sequence, IteratorProtocol {
  public mutating func next() -> Element? {
    guard !_done else { return nil }
    if let elt = _next(&_state) {
//這句可以看出為什么sequence函數(shù)的next的返回類型都是可選類型,
//當(dāng)執(zhí)行next循環(huán)語句返回nil,隊(duì)列剩余部分則不執(zhí)行next函數(shù),全部返回nil
        return elt
    } else {
        _done = true
        return nil
    }
  }
  internal init(_state: State, _next: (inout State) -> Element?) {
    self._state = _state
    self._next = _next
  }
  internal var _state: State
  internal let _next: (inout State) -> Element?
  internal var _done = false
}

兩者之間的不同之處在于,第一個(gè)更簡單的函數(shù)產(chǎn)生一個(gè)和它狀態(tài)相同類型的sequence序列。而第二個(gè)函數(shù)則將狀態(tài)類型和輸出類型區(qū)分了出來,因此你可以生成整數(shù),并且同時(shí)對(duì)字符串做出處理亚亲。

現(xiàn)在你來仔細(xì)想一想,是不是發(fā)現(xiàn)repeat-while真是就像是一個(gè)另外一種形式的sequence序列。下面我們來舉一個(gè)簡單的例子腐缤。

var i = 0
repeat {
    print(i) // some loop body
    i = i + 5
} while i <= 100

現(xiàn)在你看了上述的內(nèi)容,你可以進(jìn)行重寫,來試著把i狀態(tài)變量納入控制結(jié)構(gòu),就像這樣:

for i in sequence(first: 0, next: { $0 + 5 }) {
    print (i) // some loop body
    if i >= 100 { break } 
}

或者你可以更大膽一些,試著把所有的行為和狀態(tài)寫入next閉包中,就像這樣:

for _ in sequence(first: 0, next: {
    print($0) // some loop body
    let value = $0 + 5
    return value <= 100 ? value : nil
}) {}

這里有3件比較重要的事關(guān)于這項(xiàng)第三種寫法:
1.這個(gè)for循環(huán)不需要變量捌归。它只是被用于去執(zhí)行這個(gè)序列。
2.這個(gè)循環(huán)體是空的,它僅僅被用于完成這個(gè)語法岭粤。當(dāng)然你也可以去執(zhí)行數(shù)組(也算一個(gè)序列),但那樣將會(huì)需要申請(qǐng)內(nèi)存,那個(gè)做法是十分浪費(fèi)的惜索。
3.這個(gè)序列當(dāng)返回nil時(shí)會(huì)終止。這就意味著這個(gè)閉包的返回類型是T剃浇?,而T則是第一個(gè)參數(shù)的類型巾兆。在這個(gè)例子中return的值只可以返回?cái)?shù)字類型,因?yàn)檫@個(gè)值并沒有有意義的用途,它只是被用于檢查false/nil猎物。

如果你想結(jié)合Bool條件,有一種快速的方法,可以把Bool類型轉(zhuǎn)化為一個(gè)可選。雖然這樣做有些過了,但它的確能完成任務(wù)角塑。

extension Bool { var opt: Bool? { return self ? self : nil } }

或者,你也可以寫一個(gè)函數(shù)來處理Boolean作為控制語句,這樣你就不需要轉(zhuǎn)換Boolean作為可選蔫磨。

這個(gè)perform函數(shù)是用于創(chuàng)造一個(gè)狀態(tài)化的repeat-while循環(huán),它使用一個(gè)Boolean作為控制,封裝了sequence函數(shù)的使用,并且允許這個(gè)循環(huán)體是一個(gè)尾隨閉包。

func perform<T>(
    with state: T,
    while test: (T) -> Bool,
    repeat body: (inout T) -> Void) -> T {
    var updatedState: T = state
    let boolSequence = sequence(state: state, next: {
        (state: inout T) -> Bool? in
        body(&state)
        updatedState = state
        return test(updatedState) ? true : nil
    })
    for _ in boolSequence {}
    return updatedState
}

// 下面的示例將這些單詞連接到一個(gè)空格分隔的字符串中圃伶。
let joinedWords = perform(
    with: ["Lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit"],
    while: { $0.count > 1 })
{
    (state: inout [String]) in
    guard state.count >= 2 else { return }
    let (last, butLast) = (state.removeLast(), state.removeLast())
    let joinedLast = butLast + " " + last
    state.append(joinedLast)
}.first!

debugPrint(joinedWords)
輸出結(jié)果為:"Lorem ipsum dolor sit amet consectetur adipiscing elit"

這里最關(guān)鍵的地方是初始的單詞數(shù)組(指["Lorem", "ipsum"...])并沒有被存儲(chǔ)在循環(huán)外部的任何地方,但是可以在循環(huán)體內(nèi)操作堤如。
我相信這個(gè)特性正符合社區(qū)成員所說的"當(dāng)使用‘repeat...while’循環(huán)時(shí),循環(huán)條件依賴于那些在循環(huán)體中被聲明變量"這句話。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末窒朋,一起剝皮案震驚了整個(gè)濱河市搀罢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌侥猩,老刑警劉巖榔至,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異欺劳,居然都是意外死亡唧取,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門杰标,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兵怯,“玉大人,你說我怎么就攤上這事腔剂。” “怎么了驼仪?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵掸犬,是天一觀的道長。 經(jīng)常有香客問我绪爸,道長湾碎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任奠货,我火速辦了婚禮介褥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘递惋。我一直安慰自己柔滔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布萍虽。 她就那樣靜靜地躺著睛廊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杉编。 梳的紋絲不亂的頭發(fā)上超全,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天咆霜,我揣著相機(jī)與錄音,去河邊找鬼嘶朱。 笑死蛾坯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疏遏。 我是一名探鬼主播脉课,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼改览!你這毒婦竟也來了下翎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤宝当,失蹤者是張志新(化名)和其女友劉穎视事,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庆揩,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡俐东,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了订晌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虏辫。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖锈拨,靈堂內(nèi)的尸體忽然破棺而出砌庄,到底是詐尸還是另有隱情,我是刑警寧澤奕枢,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布娄昆,位于F島的核電站,受9級(jí)特大地震影響缝彬,放射性物質(zhì)發(fā)生泄漏萌焰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一谷浅、第九天 我趴在偏房一處隱蔽的房頂上張望扒俯。 院中可真熱鬧,春花似錦一疯、人聲如沸撼玄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽互纯。三九已至,卻和暖如春磕蒲,著一層夾襖步出監(jiān)牢的瞬間留潦,已是汗流浹背只盹。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兔院,地道東北人殖卑。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像坊萝,于是被迫代替她去往敵國和親孵稽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容