Swift的安全性是否影响性能?
在学习Swift的过程中,我看到了许多安全代码与不安全代码的对比案例。这方面的一个完美例子是 作为?和作为强> as?,据我所知,它尝试键入cast,但如果不进行cast,则返回nil as据我所知,strong>尝试键入cast,如果失败则崩溃 我的问题是,为什么会成为,(以及其他与安全对应的不安全语法)是否存在?显然,as?是更好的选择。我能想到的唯一答案是,可能使用作为对于编译器来说编译速度更快,因此主要是一种语法优化 我只是想知道,安全语法的编译速度稍微慢一点,这是对的,因为性能对我来说非常重要Swift的安全性是否影响性能?,swift,Swift,在学习Swift的过程中,我看到了许多安全代码与不安全代码的对比案例。这方面的一个完美例子是 作为?和作为 as?,据我所知,它尝试键入cast,但如果不进行cast,则返回nil as尝试键入cast,如果失败则崩溃 我的问题是,为什么会成为,(以及其他与安全对应的不安全语法)是否存在?显然,as?是更好的选择。我能想到的唯一答案是,可能使用作为对于编译器来说编译速度更快,因此主要是一种语法优化 我只是想知道,安全语法的编译速度稍微慢一点,这是对的,因为性能对我来说非常重要 谢谢您抽出时间。正
谢谢您抽出时间。正如您所说,
As代码>几乎不应该被使用。但也有一些情况,由于遗留问题,编译器不知道应该是什么类型,即使开发人员知道。这方面的一个例子是NSCopying
协议。由于Objective-C对类型安全性的要求不如Swift严格,copy()
返回一个id
,该id在Swift中桥接到任何
。然而,当你使用copy()
,mutableCopy()
和朋友时,你通常都知道你会从中得到什么类型的信息,所以也一样代码>通常用于强制转换为正确的类型
let aString: NSAttributedString = ...
let mutableAString = aString.mutableCopy() as! NSMutableAttributedString
as不是不安全的,除非之前的代码未能确保强制转换不会失败。想象一下这样一种情况:代码已经验证了对象确实可以被强制转换为特定的协议。如果出于任何原因,您觉得不创建该类型的新局部变量并将第一个变量强制转换为该类型比较方便,那么使用as!可以是适当的
同样的逻辑也适用于隐式展开的选项。由于在实例化视图控制器时,还不能指定IBOutlet属性(故事板尚未加载),因此该属性必须是可选的。但是,当您知道故事板已经加载时,必须在整个类中将该属性用作可选属性,这是令人厌烦的。事实上,如果在定位和分配故事板元素时出现问题,则需要100%保证崩溃,以便开发人员始终能够发现并修复问题
所以回到as,这引发了第二种情况,即何时适合使用:何时崩溃是失败强制转换的最理想结果
所以这与编译器的速度无关。这是关于代码逻辑的便利性。有适当的时间使用它,对于这些时间,它是一种更紧凑、更易于阅读的表示逻辑目标的方式 你可以自己调查这个问题
func f(a: Any) -> Int {
(a as! Int) + 5
}
vs
使用Swift 4编译器,在此Swift代码上运行swiftc-O-emit assembly
会产生极其相似的输出,这应该与您对的理解一致代码>有效,如果它不是语言的一部分,我们将如何实现它:
func forceCast<T>(_ subject: Any) -> T {
return subject as? T ?? fatalError("Could not cast \(subject) to \(T)")
}
func forceCast(uu主题:任意)->T{
将主题返回为?T??fatalError(“无法将\(主题)转换为\(T)”)
}
值得注意的是,正如SmartCat已经提到的,as代码>实际上并不“不安全”,因为Swift编译器的作者定义了这个词;因为它像as?
,实际上专门检查主题的类型。在swift的意义上有一种不安全的力量;毫不奇怪,它被称为unsafeBitCast
;相当于C/Objective-C cast;它不检查类型,只是假设您知道自己在做什么。它会比as
快吗?毫无疑问
所以,要回答你的标题问题:是的,Swift的安全是有代价的。硬币的另一面是,如果您编写的代码避免了强制转换和可选性,那么Swift(理论上)可以比安全性保证较差的语言更积极地优化代码
回答你的实际问题;as?
和as之间没有区别代码>在性能方面
其他人已经介绍了为什么as代码>存在;这样你就可以告诉编译器“我不能向你解释为什么,但这总是有效的;相信我。”这个问题基于一个错误的前提:作为as?
vsas的主要选择代码>通常不是性能的一种。当然,as代码>可能会更高效一些,但在优化的构建中,这种差异通常可以忽略不计
我们选择作为代码>vs作为?
基于上下文:
- 如果强制转换可能在运行时失败,那么您应该使用
as?
。当然,您可以添加代码来检查强制转换是否成功
当数据源是某个外部源(例如,用户输入或网络请求)时,可能会失败的转换的常见示例。用户可以将文本值粘贴到只需要数字值的字段中。外部web服务器可能不可用,甚至可能以意外格式返回数据。您可能希望使用as?
来检测这些情况并优雅地处理它们
- 但是如果强制转换不可能在运行时失败,那么您可以使用
as代码>。但是,您这样做并不是出于性能原因,而是出于清晰和编写简洁代码的原因
不能失败的强制转换的一个常见示例是从故事板检索单元原型时,您知道基类型是在Interface Builder中设置的,尽管Cocoa API不知道这一点。添加大量代码检查以查看基类型是否设置正确是不必要的(特别是因为这样会
func forceCast<T>(_ subject: Any) -> T {
return subject as? T ?? fatalError("Could not cast \(subject) to \(T)")
}