(正如@Hamish 在下面的评论中指出的那样,我误解了 OP 真正要问的是什么。但是,我会留下我的答案,作为关于 ! 类型注释的一些好奇和见解,这可能与此问题的未来读者相关)
对于任何类型的 String 可选项,在使用可失败的 init?(_ text: String) 初始化程序或 Int 之前,需要解开它们的值。
在您的示例中,变量 npill 是可选的,因为您已使用 ! 说明符(应谨慎使用)注释其类型。引用已实施的evolution proposal SE-0054 [强调我的]
将! 附加到 Swift 声明的类型将使其成为可选的
输入 并用一个属性注释声明 it
使用时可能会隐式展开。
因此,将npill 直接与Int 的init?(_ text: String) 初始化程序一起使用是完全合法的,因为它将在使用时即时解包(对nil 内容没有任何安全检查!)。
// UNSAFE example!
var npill: String! = "42"
if let npillInt = Int(npill) {
/* ^^^^^^^^ ^^^^^- since 'npill' has a type annotated with
| '!', it will be unsafely unwrapped at
| this point
\
the optional binding here safely unwraps the return from
the failable Int initializer, but has nothing to do with
the unwrapping of 'npill' */
print(npillInt) // 42
}
// why unsafe? consider
npill = nil
if let npillInt = Int(npill) { // runtime exception!
// ...
}
但是,通常您应该避免使用 ! 注释,除非您完全确定生成的可选变量的内容永远不会是 nil。
撇开使用! 注释的缺点不谈:您可以通过使用安全显式展开技术覆盖不安全隐式展开来实现上述不安全示例的安全版本。对于使用 ! 注释声明的给定可选变量,我们仍然可以应用安全的方法来解包它,例如可选绑定或使用 nil 合并运算符。 @appzYourLife 已经展示了一种完全有效且安全的方法来处理 npill 的展开和类型转换尝试使用可选绑定,所以我将简单地包含另一个使用 nil 合并运算符的示例:
// "safe" example (STILL: why use the `!` annotation?)
var npill: String! = "42"
if let npillInt = Int(npill ?? "x") {
/* ^^^^^ if 'npill' is 'nil', the Int initializer will
be given the value "x", which itself will lead
it to fail, which is safe here as we intend to
bind the result of the initialization to 'npillInt' */
print(npillInt) // 42
}
npill = nil
if let npillInt = Int(npill ?? "x") {
// ... doesnt enter
}
以上示例的共识是,如果我们稍微不确定npill 是否可以是nil,我们需要将其视为只是一个可选的未注释的类型!(即String?);使用变量时,使用安全方式覆盖默认的不安全展开。在这种情况下,我们为什么还要使用 ! typ 注解,因为它只会给我们的应用程序带来脆弱/危险?