鍍金池/ 教程/ iOS/ Swift 的強(qiáng)大之處
與四軸無人機(jī)的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測(cè)試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動(dòng)開發(fā)
Collection View 動(dòng)畫
截圖測(cè)試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個(gè)完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進(jìn)的自動(dòng)布局工具箱
動(dòng)畫
為 iOS 7 重新設(shè)計(jì) App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實(shí)例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動(dòng)畫解釋
響應(yīng)式 Android 應(yīng)用
初識(shí) TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項(xiàng)目介紹
Swift 的強(qiáng)大之處
測(cè)試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機(jī)制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計(jì)優(yōu)雅的移動(dòng)游戲
繪制像素到屏幕上
相機(jī)與照片
音頻 API 一覽
交互式動(dòng)畫
常見的后臺(tái)實(shí)踐
糟糕的測(cè)試
避免濫用單例
數(shù)據(jù)模型和模型對(duì)象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場(chǎng)
照片框架
響應(yīng)式視圖
Square Register 中的擴(kuò)張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點(diǎn)互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計(jì)的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計(jì)
置換測(cè)試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無人機(jī)項(xiàng)目
Mach-O 可執(zhí)行文件
UI 測(cè)試
值對(duì)象
活動(dòng)追蹤
依賴注入
Swift
項(xiàng)目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測(cè)試 View Controllers
訪談
收據(jù)驗(yàn)證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場(chǎng)
游戲
調(diào)試核對(duì)清單
View Controller 容器
學(xué)無止境
XCTest 測(cè)試實(shí)戰(zhàn)
iOS 7
Layer 中自定義屬性的動(dòng)畫
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲(chǔ)
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺
Artsy
照片擴(kuò)展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫(kù)支持
Fetch 請(qǐng)求
導(dǎo)入大數(shù)據(jù)集
iOS 開發(fā)者的 Android 第一課
iOS 上的相機(jī)捕捉
語(yǔ)言標(biāo)簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識(shí)別
玩轉(zhuǎn)字符串
相機(jī)工作原理
Build 過程

Swift 的強(qiáng)大之處

在寫任何東西之前我需要承認(rèn)我是帶有偏見的:我愛 Swift。我認(rèn)為這是從我開始接觸 Cocoa 生態(tài)系統(tǒng)以來這個(gè)平臺(tái)上發(fā)生的最好的事情。我想通過分享我在 Swift,Objective-C 和 Haskell 上的經(jīng)驗(yàn)讓大家知道我為何這樣認(rèn)為。寫這篇文章并不是為了介紹一些最好的實(shí)踐 (寫這些的時(shí)候 Swift 還太年輕,還沒最好實(shí)踐被總結(jié)出來),而是舉幾個(gè)關(guān)于 Swift 強(qiáng)大之處的例子。

給大家一些我的個(gè)人背景:在成為全職 iOS/Mac 工程師之前我花了幾年的時(shí)間做 Haskell (包括一些其他函數(shù)式編程語(yǔ)言) 開發(fā)。我仍然認(rèn)為 Haskell 是我所有使用過的語(yǔ)言中最棒的之一。然而我轉(zhuǎn)戰(zhàn)到了 Objective-C,是因?yàn)槲蚁嘈?iOS 是最令人激動(dòng)的平臺(tái)。剛開始接觸 Objective-C 的時(shí)候我有些許沮喪,但我慢慢地學(xué)會(huì)了欣賞它。

當(dāng)蘋果在 WWDC 發(fā)布 Swift 的時(shí)候我非常的激動(dòng)。我已經(jīng)很久沒有對(duì)新技術(shù)的發(fā)布感的如此興奮了。在看過文檔之后我意識(shí)到 Swift 使我們能夠?qū)F(xiàn)有的函數(shù)式編程知識(shí)和 Cocoa API 無縫地整合到一起。我覺得這兩者的組合非常獨(dú)特:沒有任何其他的語(yǔ)言將它們?nèi)诤系厝绱送昝馈>湍?Haskell 來說,想要用它來使用 Objective-C API 相當(dāng)?shù)睦щy。同樣,想用 Objective-C 去做函數(shù)式編程也是十分困難的。

在 Utrecht 大學(xué)期間我學(xué)會(huì)了函數(shù)式編程。因?yàn)槭窃诤軐W(xué)術(shù)的環(huán)境下學(xué)習(xí)所以并沒有覺得很多復(fù)雜的術(shù)語(yǔ) (moands,applicative functors 以及很多其他的東西) 有多么難懂。我覺得對(duì)很多想學(xué)習(xí)函數(shù)式編程的人來說這些名稱是一個(gè)很大的阻礙。

不僅僅名稱很不同,風(fēng)格也不一樣。作為 Objective-C 程序員,我們很習(xí)慣于面向?qū)ο缶幊?。而且因?yàn)榇蠖鄶?shù)語(yǔ)言不是面對(duì)對(duì)象編程就是與之類似,我們可以看懂很多不同語(yǔ)言的代碼。閱讀函數(shù)式編程語(yǔ)言的時(shí)候則大不相同 -- 如果你沒有習(xí)慣的話看起來簡(jiǎn)直莫名其妙。

那么,為什么你要使用函數(shù)式編程呢?它很奇怪,很多人都不習(xí)慣而且學(xué)習(xí)它要花費(fèi)大量的時(shí)間。并且對(duì)于大多數(shù)問題面向?qū)ο缶幊潭寄芙鉀Q,所以沒有必要去學(xué)習(xí)任何新的東西對(duì)吧?

對(duì)于我來說,函數(shù)式編程只是工具箱中的一件工具。它是一個(gè)改變了我對(duì)編程的理解的強(qiáng)大工具。在解決問題的時(shí)候它非常強(qiáng)大。對(duì)于大多數(shù)問題面向?qū)ο缶幊潭己馨簦菍?duì)于其他一些問題應(yīng)用函數(shù)式編程會(huì)給你帶來巨大的時(shí)間/精力的節(jié)省。

開始學(xué)習(xí)函數(shù)式編程或許有些痛苦。第一,你必須放手一些老的模式。而因?yàn)槲覀兒芏嗳顺D暧妹鎸?duì)對(duì)象的方式去思考,做到這一點(diǎn)是很困難的。在函數(shù)式編程當(dāng)中你想的是不變的數(shù)據(jù)結(jié)構(gòu)以及那些轉(zhuǎn)換它們的函數(shù)。在面對(duì)對(duì)象編程當(dāng)中你考慮的是互相發(fā)送信息的對(duì)象。如果你沒有馬上理解函數(shù)式編程,這是一個(gè)好的信號(hào)。你的大腦很可能已經(jīng)完全適應(yīng)了用面對(duì)對(duì)象的方法來解決問題。

例子

我最喜歡的 Swift 功能之一是對(duì) optionals 的使用。Optionals 讓我們能夠應(yīng)對(duì)有可能存在也有可能不存在的值。在 Objective-C 里我們必須在文檔中清晰地說明 nil 是否是允許的。Optionals 讓我們將這份責(zé)任交給了類型系統(tǒng)。如果你有一個(gè)可選值,你就知道它可以是 nil。如果它不是可選值,你知道它不可能是 nil。

舉個(gè)例子,看看下面一小段 Objective-C 代碼

- (NSAttributedString *)attributedString:(NSString *)input 
{
    return [[NSAttributedString alloc] initWithString:input];
}

看上去沒有什么問題,但是如果 input 是 nil, 它就會(huì)崩潰。這種問題你只能在運(yùn)行的時(shí)候才能發(fā)現(xiàn)。取決于你如何使用它,你可能很快能發(fā)現(xiàn)問題,但是你也有可能在發(fā)布應(yīng)用之后才發(fā)現(xiàn),導(dǎo)致用戶正在使用的應(yīng)用崩潰。

用相同的 Swift 的 API 來做對(duì)比。

extension NSAttributedString {
    init(string str: String)
}

看起來像對(duì)Objective-C的直接翻譯,但是 Swift 不允許 nil 被傳入。如果要達(dá)到這個(gè)目的,API 需要變成這個(gè)樣子:

extension NSAttributedString {
    init(string str: String?)
}

注意新加上的問號(hào)。這意味著你可以使用一個(gè)值或者是 nil。類非常的精確:只需要看一眼我們就知道什么值是允許的。使用 optionals 一段時(shí)間之后你會(huì)發(fā)現(xiàn)你只需要閱讀類型而不用再去看文檔了。如果犯了一個(gè)錯(cuò)誤,你會(huì)得到一個(gè)編譯時(shí)警告而不是一個(gè)運(yùn)行時(shí)錯(cuò)誤。

建議

如果可能的話避免使用 optionals。Optionals 對(duì)于使用你 API 的人們來說是一個(gè)多余的負(fù)擔(dān)。話雖如此,還是有很多地方可以很好使用它們。如果你有一個(gè)函數(shù)會(huì)因?yàn)橐粋€(gè)明顯的原因失敗你可以返回一個(gè) optional。舉例來說,比如將一個(gè) #00ff00 字符串轉(zhuǎn)換成顏色。如果你的參數(shù)不符合正確的格式,你應(yīng)該返回一個(gè) nil 。

func parseColorFromHexString(input: String) -> UIColor? {
    // ...
}

如果你需要闡明錯(cuò)誤信息,你可以使用 Either 或者 Result 類型 (不在標(biāo)準(zhǔn)庫(kù)里面)。當(dāng)失敗的原因很重要的時(shí)候,這種做法會(huì)非常有用。“Error Handling in Swift” 一文中有個(gè)很好的例子。

Enums

Enums 是一個(gè)隨 Swift 推出的新東西,它和我們?cè)?Objective-C 中見過的東西都大不相同。在 Objective-C 里面我們有一個(gè)東西叫做 enums, 但是它們差不多就是升級(jí)版的整數(shù)。

我們來看看布爾類型。一個(gè)布爾值是兩種可能性 -- true 或者 false -- 中的一個(gè)。很重要的一點(diǎn)是沒有辦法再添加另外一個(gè)值 -- 布爾類型是封閉的。布爾類型的封閉性的好處是每當(dāng)使用布爾值的時(shí)候我們只需要考慮 true 或者 false 這兩種情況。

在這一點(diǎn)上面 optionals 是一樣的??偣仓挥袃煞N情況:nil 或者有值。在 Swift 里面布爾和 optional 都可以被定義為 enums。但有一個(gè)不同點(diǎn):在 optional enum 中有一種可能性有一個(gè)相關(guān)值。我們來看看它們不同的定義:

enum Boolean {
    case False
    case True
}

enum Optional<A> {
    case Nil
    case Some(A)
}

它們非常的相似。如果你把它們的名稱改成一樣的話,那么唯一的區(qū)別就是括號(hào)里的相關(guān)值。如果你給 optional 中的 Nil 情況也加上一個(gè)值,你就會(huì)得到一個(gè) Either 類型:

enum Either<A,B> {
    case Left<A>
    case Right<B>
}

在函數(shù)式編程當(dāng)中,在你想表示兩件事情之間的選擇時(shí)候你會(huì)經(jīng)常用到 Either 類型。舉個(gè)例子:如果你有一個(gè)函數(shù)返回一個(gè)整數(shù)或者一個(gè)錯(cuò)誤,你就可以用 Either<Int, NSError>。如果你想在一個(gè)字典中儲(chǔ)存布爾值或者字符串,你就可以使用 Either<Bool,String> 作為鍵。

理論旁白:有些時(shí)候 enums 被稱為 sum 類型,因?yàn)樗鼈兪菐讉€(gè)不同類型的總和。在 Either 類型的例子中,它們表達(dá)的是 A 類型和 B 類型的和。Structs 和 tuples 被稱為 product 類型,因?yàn)樗鼈兇韼讉€(gè)不同類型的乘積。參見“algebraic data types.”

理解什么時(shí)候使用 enums 什么時(shí)候使用其他的數(shù)據(jù)類型 (比如 class 或者 structs)會(huì)有一些難度。當(dāng)你有一個(gè)固定數(shù)量的值的集合的時(shí)候,enum 是最有用的。比如說,如果我們?cè)O(shè)計(jì)一個(gè) Github API 的 wrapper,我們可以用 enum 來表示端點(diǎn)。比如有一個(gè)不需要任何參數(shù)的 /zen 的 API 端點(diǎn)。再比如為了獲取用戶的資料我們需要提供用戶名。最后我們顯示用戶的倉(cāng)庫(kù)時(shí),我們需要提供用戶名以及一個(gè)值去說明是否從小到大地排列結(jié)果。

enum Github {
    case Zen
    case UserProfile(String)
    case Repositories(username: String, sortAscending: Bool)
}

定義 API 端點(diǎn)是很好的使用 enum 的場(chǎng)景。API 的端點(diǎn)是有限的,所以我們可以為每一個(gè)端點(diǎn)定義一個(gè)情況。如果我們?cè)趯?duì)這些端點(diǎn)使用 switch 的時(shí)候沒有包含所有情況的話,我們會(huì)被給予警告。所以說當(dāng)我們需要添加一個(gè)情況的時(shí)候我們需要更新每一個(gè)用到這個(gè) enum 的函數(shù)。

除非能夠拿到源代碼,其他使用我們 enum 的人不能添加新的情況,這是一個(gè)非常有用的限制。想想要是你能夠加一種新情況到 Bool 或者 Optional 里會(huì)怎么樣吧 -- 所有用到 它的函數(shù)都需要重寫。

比如說我們正在開發(fā)一個(gè)貨幣轉(zhuǎn)換器。我們可以將貨幣給定義成 enum:

enum Currency {
    case Eur
    case Usd
}

我們現(xiàn)在可以做一個(gè)獲取任何貨幣符號(hào)的函數(shù):

func symbol(input: Currency) -> String {
    switch input {
        case .Eur: return "€"
        case .Usd: return "$"
    }
}

最后,我們可以用我們的 symbol 函數(shù),來依據(jù)系統(tǒng)本地設(shè)置得到一個(gè)很好地格式化過的字符串:

func format(amount: Double, currency: Currency) -> String {
    let formatter = NSNumberFormatter()
    formatter.numberStyle = .CurrencyStyle
    formatter.currencySymbol = symbol(currency)
    return formatter.stringFromNumber(amount)
}

這樣一來有一個(gè)很大的限制。我們可能會(huì)想讓我們 API 的使用者在將來可以修改一些情況。在 Objective-C 當(dāng)中向一個(gè)接口里添加更多類型的常見解決方法是子類化。在 Objective-C 里面理論上你可以子類化任何一個(gè)類,然后通過這種辦法來擴(kuò)展它。在 Swift 里面你仍然可以使用子類化,但是只能對(duì) class 使用,對(duì)于 enum 則不行。然而,我們可以用另一種技術(shù)來達(dá)到目的 (這種辦法在 Objetive-C 和 Swift 的 protocol 中都可行)。

假設(shè)我們定義一個(gè)貨幣符號(hào)的協(xié)議:

protocol CurrencySymbol {
    func symbol() -> String
}

現(xiàn)在我們讓 Currency 類型遵守這個(gè)協(xié)議。注意我們可以將 input 參數(shù)去掉,因?yàn)檫@里它被作為 self 隱式地進(jìn)行傳遞:

extension Currency : CurrencySymbol {
   func symbol() -> String {
        switch self {
            case .Eur: return "€"
            case .Usd: return "$"
        }
    }
}

現(xiàn)在我們可以重寫 format 方法來格式化任何遵守我們協(xié)議的類型:

func format(amount: Double, currency: CurrencySymbol) -> String {
    let formatter = NSNumberFormatter()
    formatter.numberStyle = .CurrencyStyle
    formatter.currencySymbol = currency.symbol()
    return formatter.stringFromNumber(amount)
}

這樣一來我們將我們代碼的可延展性大大提升類 -- 任何遵守 CurrencySymbol 協(xié)議的類型都可以被格式化。比如說,我們建立一個(gè)新的類型來儲(chǔ)存比特幣,我們可以立刻讓它擁有格式化功能:

struct Bitcoin : CurrencySymbol {
    func symbol() -> String {
        return "B?"
    }
}

這是一種寫出具有延展性函數(shù)的很好的方法。通過使用一個(gè)需要遵守協(xié)議,而不是一個(gè)實(shí)實(shí)在在的類型,你的 API 的用戶能夠加入更多的類型。你仍然可以利用 enum 的靈活性,但是通過讓它們遵守協(xié)議,你可以更好地表達(dá)自己的意思。根據(jù)你的具體情況,你現(xiàn)在可以輕松地選擇是否開放你的 API。

類型安全

我認(rèn)為類型的安全性是 Swift 一個(gè)很大的優(yōu)勢(shì)。就像我們?cè)谟懻?optionals 時(shí)看見的一樣,我們可以用一些聰明的手段將某些檢測(cè)從運(yùn)行時(shí)轉(zhuǎn)移到編譯時(shí)。Swift 中數(shù)組的工作方式就是一個(gè)例子:一個(gè)數(shù)組是泛型的,它只能容納一個(gè)類型的對(duì)象。將一個(gè)整數(shù)附加在一個(gè)字符組數(shù)組后面是做不到的。這樣以來就消滅了一個(gè)類的潛在 bug。(值得注意的是如果你需要同時(shí)將字符串或者整數(shù)放到一個(gè)數(shù)組里的話,你可以使用上面談到過的 Either 類型。)

再比如說,我們要將我們到貨幣轉(zhuǎn)換器延展為一個(gè)通用的單位換算器。如果我們使用 Double 去表示數(shù)量,會(huì)有一點(diǎn)點(diǎn)誤導(dǎo)性。比如說,100.0 可以表示 100 美元,100 千克或者任何能用 100 表示的東西。我們可以借助類型系統(tǒng)來制作不同的類型來表示不同的物理上的數(shù)量。比如說我們可以定義一個(gè)類型來表示錢:

struct Money {
    let amount : Double
    let currency: Currency
}

我們可以定義另外一個(gè)結(jié)構(gòu)來表示質(zhì)量:

struct Mass {
    let kilograms: Double
}

現(xiàn)在我們就消除了不小心將 MoneyMass 相加的可能性?;谀銘?yīng)用的特質(zhì)有時(shí)候?qū)⒁恍┖?jiǎn)單的類型包裝成這樣是很有效的。不僅如此,閱讀代碼也會(huì)變得更加簡(jiǎn)單。假設(shè)我們遇到一個(gè) pounds 函數(shù):

func pounds(input: Double) -> Double

光看類型定義很難看出來這個(gè)函數(shù)的功能。它將歐元裝換成英鎊?還是將千克轉(zhuǎn)換成磅? (英文中英鎊和磅均為 pound) 我們可以用不同的名字,或者可以建立文檔 (都是很好的辦法),但是我們有第三種選擇。我們可以將這個(gè)類型變得更明確:

func pounds(input: Mass) -> Double

我們不僅讓這個(gè)函數(shù)的用戶能夠立刻理解這個(gè)函數(shù)的功能,我們也防止了不小心傳入其他單位的參數(shù)。如果你試圖將 Money 作為參數(shù)來使用這個(gè)函數(shù),編譯器是不會(huì)接受的。另外一個(gè)可能的提升是使用一個(gè)更精確的返回值。現(xiàn)在它只是一個(gè) Double。

不可變性

Swift 另外一個(gè)很棒的功能是內(nèi)置的不可變性。在 Cocoa 當(dāng)中很多的 API 都已經(jīng)體現(xiàn)出了不可變性的價(jià)值。想了解這一點(diǎn)為什么如此重要,“Error Handling in Swift” 是一個(gè)很好的參考。比如,作為一個(gè) Cocoa 開發(fā)者,我們使用很多成對(duì)的類 (NSString vs. NSMutableString,NSArray vs. NSMutableArray)。當(dāng)你得到一個(gè)字符串值,你可以假設(shè)它不會(huì)被改變。但是如果你要完全確信,你依然要復(fù)制它。然后你才知道你有一份不可變的版本。

在 Swifit 里面,不可變性被直接加入這門語(yǔ)言。比如說如果你想建立一個(gè)可變的字符串,你可以如下的代碼:

var myString = "Hello"

然而,如果你想要一個(gè)不可變的字符串,你可以做如下的事情:

let myString = "Hello"

不可變的數(shù)據(jù)在創(chuàng)建可能會(huì)被未知用戶使用的 API 時(shí)會(huì)給你很大的幫助。比如說,你有一個(gè)需要字符串作為參數(shù)的函數(shù),在你迭代它的時(shí)候,確定它不會(huì)被改變是很重要的。在 Swift 當(dāng)中這是默認(rèn)的行為。正是因?yàn)檫@個(gè)原因,在寫多線程代碼的時(shí)候使用不可變資料會(huì)使難度大大降低。

還有另外一個(gè)巨大的優(yōu)勢(shì)。如果你的函數(shù)只使用不可變的數(shù)據(jù),你的類型簽名就會(huì)成為很好的文檔。在 Objective-C 當(dāng)中則不然。比如說,假設(shè)你準(zhǔn)備在 OS X 上使用 CIFilter。在實(shí)例化之后你需要使用 setDefaults 方法。這一點(diǎn)在文檔中有提到。有很多這樣類都是這個(gè)樣子。在實(shí)例化之后,在你使用它之前你必須要使用另外一個(gè)方法。問題在于,如果不閱讀文檔的話,經(jīng)常會(huì)不清楚哪些函數(shù)需要被使用,最后你有可能遇到很奇怪的狀況。

當(dāng)使用不可變資料的時(shí)候,類型簽名讓事情變得很清晰。比如說,map 的類簽名。我們知道有一個(gè)可選的 T 值,而且有一個(gè)將 T 轉(zhuǎn)換成 U 的函數(shù)。結(jié)果是一個(gè)可選的 U 值。原始值是不可能改變的:

func map<T, U>(x: T?, f: T -> U) -> U?

對(duì)于數(shù)組的 map 來說是一樣的。它被定義成一個(gè)數(shù)組的延伸,所以參數(shù)本身是 self。我們可以看到它用一個(gè)函數(shù)將 T 轉(zhuǎn)化成 U,并且生成一個(gè) U 的數(shù)組。因?yàn)樗且粋€(gè)不可變的函數(shù),我們知道原數(shù)組是不會(huì)變化的,而且我們知道結(jié)果也是不會(huì)改變的。將這些限制內(nèi)置在l類型系統(tǒng)中,并有編譯器來監(jiān)督執(zhí)行,讓我們不再需要去查看文檔并記住什么會(huì)變化。

extension Array {
    func map<U>(transform: T -> U) -> [U]
}

總結(jié)

Swift 帶來了很多有趣的可能性。我尤其喜歡的一點(diǎn)是過去我們需要手動(dòng)檢測(cè)或者閱讀文檔的事情現(xiàn)在編譯器可以幫我們來完成。我們可以選擇在合適的時(shí)機(jī)去使用這些可能性。我們依然會(huì)用我們現(xiàn)有的,成熟的辦法去寫代碼,但是我們可以在合適的時(shí)候在我們代碼的某些地方應(yīng)用這些新的可能性。

我預(yù)測(cè):Swift 會(huì)很大程度上改變我們寫代碼的方式,而且是向好的方向改變。脫離 Objective-C 會(huì)需要幾年的時(shí)間,但是我相信我們中的大多數(shù)人會(huì)做出這個(gè)改變并且不會(huì)后悔。有些人會(huì)很快的適應(yīng),對(duì)另外一些人可能會(huì)花上很長(zhǎng)的時(shí)間。但是我相信總有一天絕大多數(shù)人會(huì)看到 Swift 帶給我們的種種好處。