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