`catMaybe as?之间的区别? Animal`和`catMaybe as Animal?`

时间:2015-04-19 05:00:46

标签: swift casting

让我说我有这些:

class Animal {
}

class Cat: Animal {
    var meow = "meow"
}

现在我有一个变量:

var catMaybe: Cat? = /* ... */

稍后我会这样做:

var obj1 = catMaybe as Animal? // ①

它编译得很好,但我也可以编写其他代码:

var obj2 = catMaybe as? Animal // ②

这次我才收到警告。这让我感到困惑,因为我认为两者都在做同样的事情。

warning: cast from 'Cat?' to unrelated type 'Animal' always fails
         var obj4 = catMaybe as? Animal
                    ~~~~~~~~ ^   ~~~~~~

①和②之间的真正区别是什么?

EDIT1

我对后台真正发生的事情很感兴趣。我会去阅读汇编代码,找出为什么②总是失败但不幸的是我不是很擅长:(

在②中,由于Animal不是可选的,我认为编译器会知道必须先解包catMaybe,如果操作成功,请尝试将其强制转换为Animal。在任何错误的情况下,它将返回nil(因为我使用as?)为什么编译器不应用这个逻辑?什么阻止了他?

EDIT2

我正在使用swift 1.2

3 个答案:

答案 0 :(得分:1)

用?你投了一个可选项,假设你做了一个if if let object = catMaby as? Animal{ /do some code with object } 你不确定catMaby是否有value.as?是为了让我们

<强> 解释

可选表单,作为?,返回您尝试向下转换的类型的可选值。强制形式as,尝试向下转换并强制 - 将结果作为单个复合动作展开。所以,如果你不确定catMaby是Animal,请将其设置为?。如果catMaby是Animal,则检查代码中是否检查catMaby是可选的

那么?是可选值,如!是相同但如果你试图解开它会给出错误

答案 1 :(得分:0)

您收到警告,因为catMaybe是可选的。 Optionals是枚举类型,只有在打开catMaybe(使用?或!)之后,您才能获得正确的对象(Cat类型)。

由于catMaybeenum(不继承Animal),您会收到警告。

所以这应该有效:

var obj2 = catMaybe! as? Animal // upcast the real unwrapped value

第一个版本有效,因为您将catMaybe作为可选项(展开时Animal对象的可选项)

答案 2 :(得分:0)

通过混合两件事 - 选项和演员表来使这变得复杂。放弃期权,看看,然后重新引入期权可能更清楚。请注意,这是Xcode 6.3 / Swift 1.2。

这是最简单的情况:

class Animal { }
class Cat: Animal { }

let c = Cat()
let a = c as Animal  // fine

编译器知道每个Cat引用都可以保证可转换为Animal,因此它允许您使用as而无需投诉。如果你以相反的方式做到这一点:

let a: Animal = Cat()
let c = a as Cat  // compiler error

编译器抱怨as无法使用 - Animal可能不是Cat。您必须使用as?,它会返回一个可选值 - 成功转换Catnil

let a: Animal = Cat()
if let c = a as? Cat   // c will be a Cat?

当保证转换有效时,Swift还允许您使用as?

let c = Cat()
let a = c as? Animal  // a will be an Animal?

虽然它有时会向你发出一个警告,告诉你正在使用条件转换来总是成功。但它只是一个警告。

对于as vs as?而言,这几乎就是这样。 as当编译器可以确定某些强制转换是否有效时,as?会返回一个可选项,而不是。这不仅适用于超级/子类,它也适用于其他保证有效的转换,例如Swift.ArrayNSArraySometypeSometype?

现在可以添加其他可选项。假设你有:

let c: Cat? = Cat()
let a = c as Animal?  // this is fine

因此,可选Cat将使用Animal转换为可选as。这是因为选项支持协方差--Swift查看转换的可选项的内容,以及转换为可选项的内容,如果转换有效在内容上,它将允许转换。

顺便说一句,这也适用于数组:

let c: [Cat] = [Cat()]
let a = c as [Animal]

由于Cat as Animal被允许,[Cat] as [Animal]也是如此。

但是,丢弃可选项允许:

let c: Cat? = Cat()
let a = c as Animal

因为您无法使用as丢弃选项,因此不允许这样做:

let i: Int? = 1
let j = i as Int

在这里用as替换as?没有帮助 - 你仍然无法进行强制转换,所以虽然它可能会编译,但结果总是nil(编译器)可能会警告你这个。)

最后,您还可以在内部执行条件转换

let c: Animal? = Cat()
let a = c as? Cat?

但要注意!现在a的类型为Animal??,因为可选的现在包含一个可选项。因此,如果你必须这样做,你最好这样做:

let c: Animal? = Cat()
let a = c.flatMap { $0 as? Cat? }

或者,如果这不会导致编译器崩溃:-(。但代码应该是正确的。