【问题标题】:Swift Optional Type SyntaxSwift 可选类型语法
【发布时间】: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!]

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

【问题讨论】:

    标签: swift optional optional-variables optional-values


    【解决方案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)
    猜你喜欢
    • 2019-01-12
    • 2017-03-29
    • 2018-05-12
    • 1970-01-01
    • 2014-08-04
    • 2014-09-10
    • 2016-08-10
    • 1970-01-01
    • 2021-10-08
    相关资源
    最近更新 更多