使用Swift进行类型转换

时间:2016-12-31 12:28:31

标签: swift casting nserror

我试图理解as类型转换。

关于Apple文档的阅读类型转换章节,我有两种向下转换的语法(作为?和!运算符),但我没有找到关于as的任何内容。 所以我认为我应该永远不会使用这个操作符的扭结,但昨天当我用do-try-catch语句键入代码时,我遇到了这个:

catch let error as NSError {
      print(error)
}

最初,错误类型符合Error protocol。 现在使用as NSError转换,它已成为NSError类的实例。

但我的问题是:运营商做了什么? 这不是一个向下倾斜的确定..它可以用于“转换”对象吗?

修改 我不认为这是重复的。 在我的例子中,错误变量不是一个类,并且不从超类继承,所以我没有向上转换。它甚至不是pattern matching。 我已经在StackOverflow上阅读了Swift博客页面和这个帖子。

编辑2 来自Swift博客

  

Swift 1.2分离了保证转换和强制转换的概念   转换成两个不同的运算符。保证转换仍然是   使用as运算符执行,但强制转换现在使用as!   运营商。的!意味着转换可能会失败。   通过这种方式,您可以快速了解哪些转换可能会导致程序   崩溃。

上面的文字对我不起作用,因为如果我尝试使用as!运算符而不是as,编译器会抱怨我。

编辑3 即使在Using Swift with Cocoa and Obj-C文档中,它们也使用let-as?语法来检查和转换为协议。 那么,为什么在我的情况下,我不能使用它?

2 个答案:

答案 0 :(得分:1)

作为

as用于Apple已完成某些工作以在后台处理转换的类型。这些通常是Apple桥接到Swift的基础类型,并且希望您能够快速地从它们的ObjC等效物来回转换,例如:

String <-> NSString
URL    <-> NSURL
Array  <-> NSArray
Data   <-> NSData

如果您使用as?as!,这些演员表总会成功,Xcode会发出警告。在您的具体情况下,Apple在后台进行了一些干预,使Error协议和NSError可以相互转换。

作为<!/ H3>

知道对象可以转换为其他类型时,请使用as!。如果对象不可投放,则as!会使您的应用崩溃(例如,当sender实际上是UITextField时)

let button = sender as! UIButton    // you are sure that the sender is always
                                    // a UIButton or your app will crash

为α

当您不确定对象是否可以转换为其他类型时,请使用as?。在实践中,这应该是您首选的方法,您应该选择绑定以检查是否成功。如果对象不可投射,as?会生成nil

// Exit the function if the sender is not a UIButton
guard let sender = sender as? UIButton else {
    return
}

// Only execute the block if the sender is UIButton
if let button = sender as? UIButton {
    // ...
}

答案 1 :(得分:0)

首先,正如dasblinkenlight的评论中所述,您的代码段未使用 type-casting-operator 。检查 do-statement­ 的语法,您可以找到以下内容:

  

catch-clause catch­ pattern选择where-clause选择code-block­

     

模式 value-binding-pattern­

     

价值绑定模式var ­pattern | let ­pattern

     

模式 type-casting-pattern

     

type-casting-pattern is-pattern | as-pattern­

     

as-pattern pattern ­as ­type

因此, EDIT 2 没有意义, catch-clause 中没有接受as!的语法。

但是这段代码(使用 type-casting-operator )有效,所以我尝试解释如何使用as - cast。

    enum MyError: Error {
        case bad
        //...
    }
    let error: Error = MyError.bad
    let nsError = error as NSError

如EI Captain v2.0评论中的链接文章所示,as - 投射用于保证转换。我收集了一些此类转换的用例。

  • 向上转型

    class Animal {}
    class Dog: Animal {}
    let d = Dog()
    d as Animal     // upcast succeeds
    

    如文章所示,上传始终成功,因此您可以使用as

  • 指定文字类型

    let byte = 123 as UInt8
    let ch = "a" as UnicodeScalar
    

    在Swift中,文字是无类型的,因此您可以使用as来指定文字的类型

    如果Swift可以推断出文字的类型,你可以省略这样的as - 施法:

    let byte: UInt8 = 123
    let ch: UnicodeScalar = "a"
    
  • 消除重载方法的歧义

    class MyClass {
        func aMethod(_ arg: String) {
            print(arg)
        }
        func aMethod(_ arg: Int) {
            print("\"\(arg)\"")
        }
    }
    let obj = MyClass()
    let theFunc = obj.aMethod as (String)->Void
    theFunc("abc") //->abc
    
  • 始终成功的桥接

    let str: String = "a String"
    let nsStr = str as NSString
    
    let intArr: [Int] = [1,2,3]
    let nsArr = intArr as NSArray
    

    示例let nsError = error as NSError包含在此类别中,您需要仔细阅读this article,以了解为什么这是始终成功的桥接

对于 EDIT 3

您可能需要区分这两种语法:

let a: Any = 1

//Using if-let -- Optional binding, `(a as? Int)` is an expression using type-casting-operator which generates an Optional result
if let intA = (a as? Int) {
    print("\(intA) is Int")
}

//Using if-case -- pattern matching, `(let intA as Int)` is a pattern using as-pattern
if case (let intA as Int) = a {
    print("\(intA) is Int")
}

如前所述,catch引导模式,您无法在模式中使用as?