让我说我有这些:
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
~~~~~~~~ ^ ~~~~~~
①和②之间的真正区别是什么?
我对后台真正发生的事情很感兴趣。我会去阅读汇编代码,找出为什么②总是失败但不幸的是我不是很擅长:(
在②中,由于Animal
不是可选的,我认为编译器会知道必须先解包catMaybe
,如果操作成功,请尝试将其强制转换为Animal
。在任何错误的情况下,它将返回nil(因为我使用as?
)为什么编译器不应用这个逻辑?什么阻止了他?
我正在使用swift 1.2
答案 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
类型)。
由于catMaybe
是enum
(不继承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?
,它会返回一个可选值 - 成功转换Cat
或nil
:
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.Array
到NSArray
,Sometype
到Sometype?
。
现在可以添加其他可选项。假设你有:
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? }
或者,如果这不会导致编译器崩溃:-(。但代码应该是正确的。