Swift 中的安全性
Swift 是一門注重安全性的語言,如Swift官網(wǎng)的關(guān)于頁面中所言
Swift 是一門通用編程語言,采用現(xiàn)代化的方法來保證安全性與性能,套用軟件設(shè)計(jì)模式。
還有它的說明
安全性:那些顯而易見而又便捷的編程方法應(yīng)該保證是安全的。未定義的行為會(huì)破壞軟件的安全性。在軟件發(fā)布之前就要把開發(fā)者的錯(cuò)誤扼殺在萌芽之中。強(qiáng)調(diào)安全性有時(shí)會(huì)讓你覺得 Swift 語法過于嚴(yán)苛,但是它帶來的代碼的明晰從長遠(yuǎn)來看還是利大于弊的。
高性能: Swift旨在替代 C 系語言(C,C ++和Objective-C),因此 Swift 必須在絕大多數(shù)任務(wù)中與這些語言有著接近的性能指數(shù),而且性能需要具有可預(yù)測(cè)性。而且這種指數(shù)需要是一種普遍的性能指數(shù),而不是曇花一現(xiàn)的僅僅幾種任務(wù)類型的高性能。具有各種特性的語言有很多,但仍保持著如此高性能卻實(shí)屬罕見。
表現(xiàn)力: Swift 受益于計(jì)算機(jī)科學(xué)的幾十年發(fā)展,提供了開發(fā)人員期望的現(xiàn)代功能并具有有趣的語法。而且 Swift 并不止步于此,Swift 社群會(huì)關(guān)注編程語言的發(fā)展并取其精華,使得 Swift 一直保持進(jìn)化,變得更好。
舉例來說,類似 Optional 這種類型就是 Swift 考慮安全性的一個(gè)體現(xiàn),在其他的編程語言當(dāng)中,你并不能知道哪個(gè)變量可以為空(null)哪個(gè)不能,而 Optional 攜帶著改變量可能為空的信息,這就強(qiáng)制開發(fā)者去考慮可能為空的情況。對(duì)于”可空”(nullable)的類型,如果你用強(qiáng)解包符號(hào)(!)來處理該類型,有些時(shí)候它會(huì)直接 crash。Swift 的安全性相當(dāng)于一條安全帶,你可以自行解開它,但是風(fēng)險(xiǎn)也要自己來承擔(dān)。
然而在某些情況下,安全性看起來并不足夠。比如舉例來說,如果我們有一個(gè)字典,我們需要通過一些 key 來提取到返回值類型為 optional 的 value
let person: [String: String] = //...
type(of: person["name"]) // => Optional
但是如果我們對(duì)數(shù)組進(jìn)行類似的操作,我們并不會(huì)得到一個(gè) optional:
let users: [User] = //...
type(of: users[0]) // => User
原因是數(shù)組可能沒有元素,如果 users 的數(shù)組為空的話,這段程序?qū)?huì)直接crash,從這方面來看,好像Swift并沒有做到足夠安全。
Swift仍然在開放的演進(jìn)中,你可能就此問題提些建議到 Swift evolution郵件組
不,那也不會(huì)有什么改變,在 Swift evolution 的 github 庫里 ”常見駁回”提議頁 當(dāng)中描述了不會(huì)接受這項(xiàng)提議:
Array< T > 的下標(biāo)獲取操作不返回一個(gè) T 而是返回一個(gè) T? 或者 T!,當(dāng)前的數(shù)組的邏輯是故意為之,它準(zhǔn)確反映了訪問越界的數(shù)組下標(biāo)是一個(gè)邏輯錯(cuò)誤。如果改變目前的邏輯會(huì)降低數(shù)組的讀取到一個(gè)無法接受的程度,這項(xiàng)提議提出多次并不會(huì)被社區(qū)采納。
這里指出的原因是在這種特殊情況下,性能至關(guān)重要。但是如果我們回過頭來看上面引用的關(guān)于頁當(dāng)中的信息,”安全性”的地位應(yīng)該是高于”速度”的,難道安全性不應(yīng)該比速度更為重要么?
這里存在著一個(gè)根本的爭議點(diǎn),在于”安全性”一詞的定義。對(duì)于”安全性”一個(gè)普遍的理解是不 crash,而 Swift 核心成員的定義是”永遠(yuǎn)不會(huì)在無意中訪問錯(cuò)誤的內(nèi)存”。
從這點(diǎn)來看,Swift 的下標(biāo)操作是”安全的”,它永遠(yuǎn)都不會(huì)去訪問在數(shù)組自身分配之外的內(nèi)存,當(dāng)你想訪問數(shù)組越界的內(nèi)存時(shí)它會(huì)立即 crash,如 Optional 類型避免了當(dāng)前存在的各種空指針引用的 bug 一樣,數(shù)組這里的考慮避免了緩沖區(qū)溢出的 bug。
Chris Lattner(Swift 作者)在這段采訪的24.39處有段說明
我們采用的安全性策略是在綜合的一種妥協(xié)。我們想使Swift成為一門安全的編程語言,但這種安全并不是沒有bug,而是我們保障內(nèi)存安全的的基礎(chǔ)上同時(shí)提供高性能而且采用一直前進(jìn)的編程語言范式。
或許,內(nèi)存安全相對(duì)于安全是一個(gè)更好的名詞,有些開發(fā)者可能更偏向于得到一個(gè) optional 的返回值,而不是在數(shù)組越界訪問的問題里糾結(jié),每個(gè)人都同意直接讓程序crash會(huì)好過讓程序攜帶著非法的數(shù)據(jù)繼續(xù)運(yùn)行下去,而這種情況還可能會(huì)被棧溢出的攻擊所利用。
第二種權(quán)衡(直接 crash 而不是允許越界訪問)的決定看起來顯而易見,但是有些語言不會(huì)做這種保證,在 C 中,訪問越界的數(shù)組將會(huì)導(dǎo)致未知的行為(具體取決于使用的編譯器對(duì)這種行為的實(shí)現(xiàn)),在 Swift 中開發(fā)者會(huì)快速的意識(shí)到自己犯了類似數(shù)組越界的錯(cuò)誤,Swift團(tuán)隊(duì)覺得這是一個(gè)合適的 crash 時(shí)機(jī),所以并不會(huì)返回一個(gè) optional 甚至是返回一段未知的數(shù)據(jù)。
使用這里”安全”的定義也明確了”不安全”的 API 的定義,因?yàn)樗鼈冎苯釉L問內(nèi)存進(jìn)行編程,程序員們自己必須十分小心保證自己不會(huì)訪問到無效的內(nèi)存,這點(diǎn)尤為困難,即使專家在這種情景也會(huì)犯錯(cuò),如果對(duì)這個(gè)主題感興趣去查閱 Matt Gallagher的博客中以安全的方式橋接 C 到 Swift 的相關(guān)討論。
Swift 的團(tuán)隊(duì)對(duì)于安全的定義可能與你預(yù)想的并不完全一致,但是它們的種種策略確實(shí)可以避免大多數(shù)的程序員去考慮各種常見的 bug,將“安全”的定義細(xì)化為“內(nèi)存安全”可以讓我更好的理解 Swift 團(tuán)隊(duì)對(duì)于安全的定義。
本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán),最新文章請(qǐng)?jiān)L問 http://swift.gg。
