"as?", "as!",和"as"之间有什么区别?它们与编程有关。

58

在升级到 Swift 1.2 之前,我可以写下以下这行代码:

if let width = imageDetails["width"] as Int?

现在它强迫我写下这句话:

if let width = imageDetails["width"] as! Int?

我的问题是,如果我被迫按照上述方式编写代码,那么我是否可以只写下方的代码,它会执行相同的功能?在所有imageDetails的值中,它会给我相同的结果吗?

if let width = imageDetails["width"] as Int
3个回答

71

as关键字用于进行向上转型和向下转型:

// Before Swift 1.2
var aView: UIView = someView()

var object = aView as NSObject // upcast 

var specificView = aView as UITableView // downcast

向上转型指从派生类到基类的转换,可以在编译时进行检查,永远不会失败。

然而,向下转型可能会失败,因为您不能总是确定特定的类。如果您有一个UIView,则可能是UITableView或UIButton。如果您的向下转型转到正确的类型 - 那太棒了!但是,如果您错误地指定了类型,则会出现运行时错误,应用程序将崩溃。

在Swift 1.2中,向下转型必须使用as?进行可选项处理或使用as!进行“强制失败”处理。如果您对类型确信无疑,则可以使用as!进行强制转换,类似于如何使用隐式解包的可选项:

// After Swift 1.2
var aView: UIView = someView()

var tableView = aView as! UITableView

感叹号可以让人们清楚地知道你知道自己在做什么,如果你意外混淆了类型,事情可能会出现严重问题!
像往常一样,使用可选绑定加问号是最安全的方式:
// This isn't new to Swift 1.2, but is still the safest way
var aView: UIView = someView()

if let tableView = aView as? UITableView {
  // do something with tableView
}

我从一个网站上得到了这个内容:来源


谢谢Jacobson!还有一个问题 - 有时我会混淆将Int版本向下转换为“转换”为Float。如果您有一个整数值,但想要转换为浮点数,您会向下转换还是转换?那么对于具有整数值的Float呢?(即2.0) - Alex

49

as

在Swift 1.2及以后版本中,as只能用于向上转型(或消除歧义)和模式匹配

// 'as' for disambiguation
let width = 42 as CGFloat
let block = { x in x+1 } as Double -> Double
let something = 3 as Any?  // optional wrapper can also be added with 'as'


:一个空段落。
// 'as' for pattern matching
switch item {
case let obj as MyObject:
    // this code will be executed if item is of type MyObject
case let other as SomethingElse:
    // this code will be executed if item is of type SomethingElse
...
}

as?

条件转换运算符as?尝试执行转换,但如果无法转换,则返回nil。因此,它的结果是可选的。

let button = someView as? UIButton  // button's type is 'UIButton?'

if let label = (superview as? MyView)?.titleLabel {
    // ...
}

as!

as!运算符用于进行强制类型转换。

只有在确信向下转换一定会成功时,才使用类型转换操作符的强制形式(as!)。如果尝试向下转换到错误的类类型,则此操作符的强制形式将触发运行时错误

// 'as!' for forced conversion.
// NOT RECOMMENDED.
let buttons = subviews as! [UIButton]  // will crash if not all subviews are UIButton
let label = subviews.first as! UILabel

3
谢谢 @jtbandes。这个答案比被采纳的答案更好。 - Junfeng
1
回复7stud,当你像输入文字这样做某事时,它会产生影响:从答案中取第一个例子let width = 42 as? CGFloat会产生一个Optional<CGFloat>,而let width = 42 as CGFloat只是一个CGFloat。在那里使用可选项没有好的理由;该值保证存在。 - jscs
@JoshCaswell 我会期望编译器在那里发出警告,告诉你强制转换总是成功的。如果没有,也许值得报告一个错误 :) - jtbandes
对于条件转换,确实,@jtbandes,我确实收到了一个警告。这是另一个很好的观点,谢谢。我仍然不完全理解Swift转换,这导致我找到了这个非常有帮助的答案! - jscs
@JoshCaswell,对我来说,as! 在你的示例中与 as 做的事情似乎完全相同。因此,再次使用 as 进行强制转换似乎是多余的。 - 7stud
显示剩余2条评论

0

正确的习语应该可以完全满足您的要求(至少在Swift的所有版本中,包括1.2),是as?可选转换。

if let width = imageDetails["width"] as? Int

可选强制转换返回一个可选项(在这种情况下为Int?),并在运行时进行测试。您的原始代码可能强制将类型转换为可选类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接