Skip to content

DeveloperLx/safety_in_swift_translation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 

Repository files navigation

Swift中的安全

Swift通常被描述为一个安全的语言。的确,在 swift.org 关于 页面中,提到了:

Swift是一种通用的编程语言,采用现代化的方式来构建安全、高性能和软件设计模式进行构建。

       以及    

  • 安全。 写代码最显而易见的,是应当以安全的方式来表现。未定义的行为是安全的敌人,开发者的错误应当要在产品上线前被捕捉到。选择了安全,就意味着swift会显得很严格,但我们认为这样的清晰长期来看是可以节省时间的。

  • 快速。 Swift旨在代替基于C的语言(C,C++,和Objective-C)。因此,对于大多数的任务,Swift必须在性能上可与之相比。且性能必须是可预测且稳定的,不仅仅是那种在短期内还需要清理的快速。很多的语言都具有着新奇的特性 – 但很少会有快速这一条。

  • 表现力。 表现力。Swift获益于计算机科学几十年的进步,提供了现代的特性开发者所期望的,乐于去使用的语法。但Swift从不止步。我们将监控语言的进步,并拥抱有效的部分,持续地改进使Swift变得更好。

例如,当用到 Optional 类型的对象时,很明显它是如何增强Swift的安全性的。在之前,你是无法知道哪个变量是可以为空,哪个是不可以的。有了这个可为空的信息后,你就必须显式地处理为空时的情形了。当使用这些“nullable”类型时,你可以选择崩溃掉,通常使用一个“ ! ”的操作符。“安全”在这里的含义是很明显的。它是你可以选择去解开的“安全带”,但风险要由你自己承担。

然而,在其它的情形下,似乎是缺乏安全性的。让我们来看一个例子。如果我们有一个字典,通过给定的键来获取相应的值,将返回可选的类型:

let person: [String: String] = //... type(of: person["name"]) // =>Optional<String>

但我们在数组上做相同的事的时候,得到的却并非是可选的类型:

let users: [User] = //... type(of: users[0]) // => User

为何如此呢?这个数组可能是空的。如果 users 这个数组是空的,那程序就没有选择,只能崩溃。这很难是安全的。我可不想被老板罚钱!

嗯,好吧。Swift有一个开放的开发过程。或许我们可以建议一项改动到 swift evolution 的mailing列表中,然后-

不,这也不行!在 swift-evolution 这个GitHub repo, “commonly rejected” proposals 提案的页面中,声明了他们是不会接受这样的变化的:

  • 使 Array<T> 的下标访问方式返回 T? T! 而不是 T :当前数组的这个行为是 有意图的 ,它精确地反映了数组越界是逻辑错误的这一事实。改变这一行为会使 Array 的访问速度降低到一个不可接受的程度。这个话题之前已被提到过了 次,但确实是不大可能被接受的。

给出了什么?它阐明的原因是,在这种情况下,速度太重要了。但回到上面的关于页面,对于这个语言的描述中,“安全”是被列为“快速”之前的。安全难道不应该比速度更为重要么?

这里有一个基本的争论,解决的要点则在于对“安全”一词的定义。尽管通常对于“安全”的理解是更多或更少的“不要崩溃”,但Swift的核心成员常常会使用相同的词语来表示“永远不会无意识地访问到错误的内存”。

在这种含义之下,Swift的 Array 下标就是“安全”的了。它永远都不会在内存中返回超越数组本身所分配的范围之外的数据。它会在给出你本不应该包含的内存中的句柄前崩溃掉。相同的方式,可选类型避免了现有的整个类型的错误(null解除引用),而这个行为则防止了不同类型错误的存在(缓冲溢出)。

你可以听到Chris Lattner的区分, 在他被ATP采访中的24分39秒

          我们说,在社区破坏的成本方面,唯一可以讲得通的方式,是如果我们把它变成为一种安全的编程语言:不是“你不会有bug”,而是在内存方面的“安全”, 同时提供高性能,以及推动编程模型向前发展。

或许“内存安全”是一个比“安全”更好的术语。这个想法是,尽管一些应用的编程者会更喜欢返回可选的类型,而不是捕获超出范围的数组访问,但每个人都可以同意,他们宁愿让程序崩溃,也不要让程序带有包含无效数据的变量,或可能会在缓冲溢出的攻击中被利用的变量继续下去。

尽管第二个权衡(崩溃而不是允许缓冲溢出)可靠看起来很明显,一些语言 并不能 给你这样的包装。在C语言中,访问数据越界会得到未知的行为,意味着任何事都可能发生,具体则依赖于你所使用的编译器的实现。特别是当编程者可以快速被告知它们犯了一个错误的情况下,Swift的团队则表示了,他们认为这是一个可以接受崩溃的地方(一直都是!),而不是返回一个可选类型,并明确地代替返回垃圾内存。

使用这个“安全”的定义也阐明了“不安全”API的设计意图。因为他们直接在内存中“鬼混”(muck about),编程者自己就必须特别小心,来 确保 它永远都不会访问无效的内存。这是非常困难的,甚至专家也会出错。关于这个话题的有趣的读物,请查看 Matt Gallagher的帖子 :以安全的方式将C连接到Swift。

Swift和核心团队对于“安全”的定义和你可能并不是100%相同的,但他们确实可以防止很多类型的错误,以便像你这样的编程者无需每天都考虑它们。通常,将它们使用的“安全”替换为“内存安全”,可以帮助理解他们的意图。

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published