Swift 可选类型语法

Posted

技术标签:

【中文标题】Swift 可选类型语法【英文标题】:Swift Optional Type Syntax 【发布时间】:2014-06-11 19:10:19 【问题描述】:

根据 Apple 的 Swift 指南,当您拥有以下 Array 和以下函数来搜索 Array 时:

let namesArray = ["John", "Lisa", "Bill", "Jennifer"]

// Note this function is set-up to return an OPTIONAL Int:
func findName (personName:String, arrayToSearchIn:String[]) -> Int? 
    for (indexOfName, nameValue) in enumerate(arrayToSearchIn) 
       if nameValue == personName 
          return indexOfName
       
    
    return nil

...因此您可以捕获此函数返回的 Optional Int - 然后检查其是否为 nil - 以下列方式:

let nameIndex: Int? = findName("Lisa", arrayToSearchIn: namesArray)
if nameIndex 
    println("found \(namesArray[nameIndex!])")

else 
    println("NOT found")

这一切都很好 - 但他们的下一个示例,他们通过将 2 个语句合并为一个来简化代码 - 让我感到困惑,因为他们突然放弃了可选的“?”和 ”!”从他们的语法来看:

if let nameIndex = findName("Lisa", arrayToSearchIn: namesArray) 
   println("found \(namesArray[nameIndex])")

而且效果很好。

那么为什么在第一个示例中nameIndex 被声明为“?” - 像这样:

nameIndex:Int?

并且使用“!”进行强制解包

[nameIndex!]

但在第二个示例中,“?”都不是。或者 ”!”一个在语法中使用?

【问题讨论】:

【参考方案1】:

if let 中声明的处理是特殊的;应该将其视为自己的语言结构(而不​​是iflet 的简单组合)。在

if let nameIndex = findName("Lisa", arrayToSearchIn: namesArray) 
   println("found \(namesArray[nameIndex]")

nameIndex的类型不需要表达,因为可以推断为findName()的返回类型Int?。在if let ... 的主体中,nameIndex 的值未绑定到 可选,因此不需要展开 - 值将是 Int

下面是如何处理if let 绑定的示例。请注意,类型的显式声明基本上被忽略了:

> func test () -> Int?  return 111 
> if let x : Int? = test ()  return x 
$R6: Int? = 111
> if let x : Int = test ()  return x 
$R7: Int = 111
> if let x = test ()  return x 
$R8: Int = 111

但如果您尝试在 if let 之外变得如此“灵活”,则会从编译器中得出错误:

> let y : Int = test ()
<REPL>:33:15: error: value of optional type 'Int?' not unwrapped; 
   did you mean to use '!' or '?'?

【讨论】:

(抱歉编辑)所以我明白你所说的不需要显式声明 nameIndex 的类型,因为类型推断会自动解决这个问题 - 但不应该这适用于两种情况吗?为什么在第一种情况下我们 do 必须指定我们想要一个 Optional 并且我们想要强制解包它 - 但在第二种情况下,我们没有截断的 if let 语句这样做? 这是因为 if let 正在通过将 nameIndex 绑定到它的实际值来为您解包。 @sirab333:在您的第一个代码中,nameIndex 的类型为 Int?。您可以显式指定类型或让它推断它;两者都可以。在您的第二个代码中,nameIndex 的类型为 Int。同样,您可以明确指定它或让它推断它。因为在第一种情况下它是Int?,所以它需要被解包。在第二种情况下,它已经是Int @newacct:这并没有加起来:在这两种情况下,nameIndex 最终都被分配了函数findName 返回的值——它被明确声明为返回一个可选的Int?,不是常规的 Int。所以在这两种情况下,nameIndex also 最终不会是 Int? 类型 - 要么因为它也被明确声明为这样,要么因为它会被 推断 鉴于它捕获了函数返回的Int??或者,您是说 any var 声明为常规 var 而不是可选的,自动 强制解开分配的任何内容? @sirab333:在第二种情况下,nameIndex 不是“分配了函数 findName 返回的值”。它是特殊的if let 语法。这与执行let 然后测试变量不同。在if let foo = bar 中,如果bar 的类型为T?,则foo 的类型为T。仅当bar 不是nil 时才分配foo,然后才解包为foo【参考方案2】:

? 是显式声明可选类型的运算符。 ! 是强制解包可选的运算符。示例中的语法是一种特殊的 Swift 简写,用于在一个简洁的行中检查和展开。它说,“将nameIndex 分配给findName(...) 的结果,如果不是nil,则运行以下代码:...”

【讨论】:

感谢您花时间回答这个问题,但恐怕您误解了我的问题。我不是在问 ?! 做什么。我知道他们在做什么——而且我完全明白这里使用的速记。我在问为什么?! 必须在第一个示例中使用,而不是在第二个速记示例中。似乎类型推断应该适用于两者,而不是只适用于一个,而不是另一个。有什么想法吗? 我不知道类型推断在第一个示例中是如何工作的。如果您完全删除该类型会发生什么?我相信如果你将它声明为Int 而不是Int?,你会得到一个错误,但是如果你完全放弃这个类型怎么办:let nameIndex = findName("Lisa", arrayToSearchIn: namesArray)

以上是关于Swift 可选类型语法的主要内容,如果未能解决你的问题,请参考以下文章

Swift 基本语法2

Swift 基本语法2

Swift初见Swift可选值Optionals

为啥你可以在 Swift 中为可选类型分配非可选值?

[Swift]学习笔记-可选类型/可选链

关于swift中的可选类型