【问题标题】:What does an exclamation mark mean in the Swift language?Swift 语言中的感叹号是什么意思?
【发布时间】:2014-07-23 23:24:36
【问题描述】:

The Swift Programming Language guide 有以下例子:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { println("\(name) is being deinitialized") }
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    var tenant: Person?
    deinit { println("Apartment #\(number) is being deinitialized") }
}

var john: Person?
var number73: Apartment?

john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)

//From Apple's “The Swift Programming Language” guide (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html)

然后在将公寓分配给该人时,他们使用感叹号“打开实例”:

john!.apartment = number73

“打开实例”是什么意思?为什么有必要?与仅执行以下操作有何不同:

john.apartment = number73

我对 Swift 语言非常陌生。只是想了解基础知识。


更新:
我遗漏的最大难题(未在答案中直接说明 - 至少在撰写本文时没有)是当您执行以下操作时:

var john: Person?

这并不意味着“john 的类型为 Person,它可能为 nil”,正如我最初所想的那样。我只是误解了PersonPerson? 是完全不同的类型。一旦我掌握了这一点,所有其他 ?! 的疯狂,以及下面的精彩答案,都会变得更有意义。

【问题讨论】:

    标签: swift optional forced-unwrapping


    【解决方案1】:

    “打开实例”是什么意思?为什么有必要?

    据我所知(这对我来说也很新鲜)......

    “包裹”一词意味着我们应该将可选变量视为礼物,包裹在闪亮的纸中,可能(可悲!)是空的

    当“包装”时,可选变量的值是一个具有两个可能值的枚举(有点像布尔值)。此枚举描述变量是否包含值 (Some(T)),或不包含值 (None)。

    如果有值,可以通过“解包”变量来获得(从Some(T)获取T)。

    john!.apartment = number73john.apartment = number73 有何不同? (转述)

    如果你写了一个可选变量的名称(例如文本john,没有!),这指的是“包装”的枚举(Some/None),而不是值本身(T)。所以john 不是Person 的实例,也没有apartment 成员:

    john.apartment
    // 'Person?' does not have a member named 'apartment'
    

    实际的Person 值可以通过多种方式展开:

    • "forced unwrapping": john!(如果存在则给出Person值,如果为nil则给出运行时错误)
    • “可选绑定”:if let p = john { println(p) }(如果值存在则执行println
    • “可选链接”:john?.learnAboutSwift()(如果值存在,则执行这个虚构的方法)

    我猜你会选择其中一种解包方式,这取决于在 nil 情况下应该发生什么,以及发生的可能性有多大。这种语言设计强制显式处理 nil 情况,我认为这比 Obj-C 提高了安全性(很容易忘记处理 nil 情况)。

    更新

    感叹号也用于声明“隐式解包选项”的语法中。

    在到目前为止的示例中,john 变量已被声明为var john:Person?,它是一个 Optional。如果您想要该变量的实际值,则必须使用上述三种方法之一解开它。

    如果它被声明为var john:Person!,则该变量将是一个隐式展开的可选项(请参阅Apple 书中带有此标题的部分)。访问值时无需解包此类变量,无需额外语法即可使用john。但苹果的书说:

    当变量有可能在以后变为 nil 时,不应使用隐式展开的选项。如果您需要在变量的生命周期内检查 nil 值,请始终使用正常的可选类型。

    更新 2

    Mike Ash 的文章“Interesting Swift Features”为可选类型提供了一些动力。我认为它是伟大的,清晰的文字。

    更新 3

    另一篇关于隐式展开的可选感叹号使用的有用文章:Chris Adamson 的“Swift and the Last Mile”。文章解释说,这是 Apple 的一种实用措施,用于声明其 Objective-C 框架使用的可能包含 nil 的类型。将类型声明为可选(使用?)或隐式展开(使用!)是“安全性和便利性之间的权衡”。在本文给出的示例中,Apple 选择将类型声明为隐式展开,从而使调用代码更方便,但安全性较低。

    也许 Apple 可能会在未来梳理他们的框架,消除隐式展开(“可能永远不会为 nil”)参数的不确定性,并用可选参数替换它们(“在特别 [希望,记录在案!] 情况下,肯定可能是 nil”)或标准的非可选(“从不为零”)声明,基于其 Objective-C 代码的确切行为。

    【讨论】:

    • 我不确定这个解释。如果您只运行没有 ! 的代码它仍然返回实际值。也许!是为了速度?
    • 好的。所以文档谈论使用!当你确定它可以被打开时。但是您可以在没有它的情况下正常运行代码(列表的第四个选项 - 隐式展开)并且无需先检查。如果为零,则返回值或为零。但是,如果您确定它不是 nil 则使用 !......但我仍然不明白您为什么要这样做?
    • 嗨@RichardWashington - 我已经为我的答案添加了一个更新,希望能澄清其中的一些内容。
    • Update 3 正是我正在寻找的。在阅读它之前,我认为 Apple 在返回 NSURLCredential 之类的东西时是在撒谎!实际上可能为零。
    • 感谢@Ashley 的精彩回答。在阅读了这个答案和苹果的一些示例 swift 代码之后,在我看来,在安全性和生产力之间的这种权衡中,通常最好是在更安全的一边。我发现一个值得注意的例外是 Apple 对 UI 元素使用强制展开,这是有道理的,因为首先,当涉及故事板时,UI 元素通常是可选的(因为它们没有以编程方式分配值),其次因为它们几乎除非它们包含的视图控制器为 nil,否则永远不会为 nil,在这种情况下,此讨论将没有实际意义。
    【解决方案2】:

    这就是我认为的区别:

    var john: Person?
    

    意味着 john 可以为 nil

    john?.apartment = number73
    

    编译器会将这一行解释为:

    if john != nil {
        john.apartment = number73
    }
    

    虽然

    john!.apartment = number73
    

    编译器会将这一行解释为:

    john.apartment = number73
    

    因此,使用! 将解开 if 语句,使其运行得更快,但如果 john 为 nil,则会发生运行时错误。

    所以这里的wrap不是说是内存包装,而是说是代码包装,在这种情况下是用if语句包装的,而且因为Apple非常关注运行时的性能,他们想给你一种让您的应用以最佳性能运行的方法。

    更新:

    4 年后回到这个答案,因为我在 Stackoverflow 中获得了最高的声誉 :) 我当时有点误解了解包的意思。现在经过 4 年,我相信在这里展开的意义是将代码从其最初的紧凑形式扩展。这也意味着消除该对象周围的模糊性,因为我们不确定它是否为 nil。就像answer of Ashley above 一样,把它想象成一个不能包含任何东西的礼物。但我仍然认为解包是代码解包,而不是使用枚举基于内存的解包。

    【讨论】:

    • 在我的操场上 john.apartment = number73 不编译,你必须指定 john?.apartment = number73
    • @ChuckPinkert 是对的,第 4 行应该编辑为 john?.apartment = number73,不过答案很好!
    • john.apartment = number73 给出错误:可选类型 'Person?' 的值未解包:您的意思是使用“!”还是“?”?
    • 展开与性能无关。 “nil 检查”仍然必须在运行时完成,唯一的区别是如果 Optional 中没有值,则会引发运行时错误。
    【解决方案3】:

    TL;DR

    感叹号在 Swift 语言中是什么意思?

    感叹号有效地表示:“我知道这个可选 绝对有价值;请使用它。”这被称为强制解包可选值:

    例子

    let possibleString: String? = "An optional string."
    print(possibleString!) // requires an exclamation mark to access its value
    // prints "An optional string."
    
    let assumedString: String! = "An implicitly unwrapped optional string."
    print(assumedString)  // no exclamation mark is needed to access its value
    // prints "An implicitly unwrapped optional string."
    

    来源:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399

    【讨论】:

    • 您的回答很棒,因为我了解发生了什么。我不明白为什么存在隐式展开的选项。为什么要创建定义为隐式展开的可选字符串而不是常规字符串类型的东西?此后的用法相同。我错过了什么?
    • 这似乎不再是真的了。在 Swift 5 repl 中,如果我先执行let f: String! = "hello",然后执行print(f),则输出为Optional("hello") 而不仅仅是"hello"
    【解决方案4】:

    如果 john 是一个可选变量(如此声明)

    var john: Person?
    

    那么 john 可能没有任何价值(在 ObjC 的说法中,nil 值)

    感叹号基本上告诉编译器“我知道这有一个值,你不需要测试它”。如果你不想使用它,你可以有条件地测试它:

    if let otherPerson = john {
        otherPerson.apartment = number73
    }
    

    this 的内部只会评估 john 是否有值。

    【讨论】:

    • 感谢您的回复,我现在明白了什么感叹号说的是,我仍在努力解决为什么...你说它告诉编译器“我知道这有一个值,你不需要测试它”。当编译器不对其进行测试时,它能给我带来什么?如果没有感叹号,编译器会抛出错误吗(我还没有可以测试 Swift 的环境)?是个 !所有可选变量都需要 100% 吗?如果是这样,苹果为什么要打扰它,而不是仅仅让它缺乏的!意思是“我知道这有一个价值,你不需要测试它”?
    • “编译器是否会抛出错误” - 不,它仍然可以正常工作,按预期返回值。我不明白这个。是个 !当你确定的时候只是为了速度?
    • 事实上,稍后在文档中使用以下示例讨论了隐式展开的选项:“let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string.” 但它可以在没有 ! 的情况下正常工作。这里似乎有些奇怪。
    • @RichardWashington 你有充分的理由感到困惑!文档中的示例遗漏了一些内容,并且具有误导性,因为它们所做的只是使用 println。显然,至少有几个实例不需要解包选项。一种是在使用 println 时。另一个是使用字符串插值时。那么,也许 println 和字符串插值在幕后展开?也许有人对此有更深入的了解。查看 Xcode6 Beta 标头定义并没有向我透露任何关于这种魔力的信息。
    • 是的,我知道John?John 是两种不同的类型。一个是 Optional Person 类型,另一个是 Person 类型。可选的 Person 需要先解包,然后才能将 Person 取出。但正如你所说,这似乎至少在这些情况下发生,而无需实际做任何事情。这似乎使!多余的。除非!始终是可选的,但建议采取措施来捕获编译时错误。有点像将 vars/let 分配给特定类型可以是显式的let John: Person = ...,但也可以推断为let John = ...
    【解决方案5】:

    一些大局观可以添加到其他有用但更注重细节的答案中:

    在 Swift 中,感叹号出现在几种情况下:

    • 强制解包:let name = nameLabel!.text
    • 隐式解包选项:var logo: UIImageView!
    • 强制转换:logo.image = thing as! UIImage
    • 未处理的异常:try! NSJSONSerialization.JSONObjectWithData(data, [])

    每一个都是具有不同含义的不同语言结构,但它们都有三个重要的共同点:

    1。感叹号绕过了 Swift 的编译时安全检查。

    当您在 Swift 中使用 ! 时,您实际上是在说,“嘿,编译器,我知道您认为这里可能会发生错误,但我知道完全确定它永远不会。”

    并非所有有效代码都适合 Swift 的编译时类型系统——或者任何语言的静态类型检查,就此而言。在某些情况下,您可以从逻辑上证明永远不会发生错误,但您无法向编译器 证明它。这就是 Swift 的设计师首先添加这些功能的原因。

    但是,无论何时使用 !,您都排除了错误的恢复路径,这意味着……

    2。感叹号是潜在的崩溃。

    感叹号还说:“嗨,斯威夫特,我非常确定这个错误永远不会发生,你最好让我的整个应用崩溃让我为其编写恢复路径。”

    这是一个危险的断言。 可能是正确的:在您仔细考虑过代码的不变量的关键任务代码中,虚假输出可能比崩溃更糟糕。

    但是,当我在野外看到! 时,很少有人如此认真地使用它。相反,它通常意味着,“这个值是可选的,我并没有认真考虑为什么它可能是 nil 或者如何正确处理这种情况,但是添加 ! 使它编译……所以我的代码是正确的,对吧?”

    当心感叹号的傲慢。而是……

    3。感叹号最好少用。

    这些! 构造中的每一个都有一个? 对应物,它迫使您处理错误/零情况:

    • 有条件的展开:if let name = nameLabel?.text { ... }
    • 可选:var logo: UIImageView?
    • 条件转换:logo.image = thing as? UIImage
    • Nil-on-failure 异常:try? NSJSONSerialization.JSONObjectWithData(data, [])

    如果您想使用!,最好仔细考虑为什么不使用?。如果! 操作失败,让你的程序崩溃真的是最好的选择吗? 为什么该值是可选/可失败的?

    在 nil/error 情况下,您的代码是否有合理的恢复路径?如果是,请编码。

    如果它不可能为 nil,如果错误永远不会发生,那么有没有一种合理的方法来重新设计你的逻辑,以便编译器知道这一点?如果是这样,那就去做;您的代码将不易出错。

    有时没有合理的方法来处理错误,而简单地忽略错误——从而处理错误的数据——会比崩溃更糟糕那些是使用强制展开的时间。

    我会定期在我的整个代码库中搜索 ! 并审核它的每次使用。很少有用法经得起审查。 (在撰写本文时,整个 Siesta 框架正好有 two instances 。)

    这并不是说您应该从不在您的代码中使用! — 只是您应该谨慎地使用它,并且永远不要将其设为默认选项。 p>

    【讨论】:

    • func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { if(receiptData == nil) { return false; } return (hasValidTrial(receiptData!) || isNotExpired(receiptData!)) && isNotCancelled(receiptData!) } Given 3.有没有更好的写法?
    • 你可以说func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { guard let nonNilReceiptData = receiptData else { return false} return (hasValidTrial(nonNilReceiptData) || isNotExpired(nonNilReceiptData)) && isNotCancelled(nonNilReceiptData) }
    • 感叹号不会绕过任何安全检查。如果可选项为 nil,您将得到 保证 崩溃。可选的总是被选中。这只是一种非常残酷的安全检查方式。
    • @gnasher729 正如答案所述,它绕过了 compile-time 安全检查,以支持安全的 runtime 故障。
    【解决方案6】:

    john 是可选的var,它可以包含nil 值。为确保该值不为零,请在 var 名称的末尾使用 !

    来自文档

    “一旦您确定可选项确实包含一个值,您就可以通过在可选项名称的末尾添加一个感叹号 (!) 来访问它的基础值。感叹号有效地表示,“我知道这个可选的肯定是有价值的;请使用它。”

    另一种检查非零值的方法是(可选展开)

        if let j = json {
            // do something with j
        }
    

    【讨论】:

    • 是的,我在文档中已经看到了,但它似乎仍然没有必要......因为,对我来说,john.apartment = number73 还说“我知道这个可选的肯定有一个价值;请使用它."...
    • 是的,但关键是默认情况下 Swift 会尝试在编译时捕获错误。如果您知道或认为您知道此变量不能包含 nil,则可以使用感叹号删除该检查。
    【解决方案7】:

    这里有一些例子:

    var name:String = "Hello World"
    var word:String?
    

    其中word 是一个可选值。表示它可能包含也可能不包含值。

    word = name 
    

    这里name 有一个值,所以我们可以分配它

    var cow:String = nil
    var dog:String!
    

    dog 被强制解包意味着它必须包含一个值

    dog = cow
    

    应用程序将崩溃,因为我们将 nil 分配给未包装

    【讨论】:

    • var c:Int = nil 将得到:“Nil 无法初始化指定类型'int'”
    【解决方案8】:

    在这种情况下...

    var John:人!

    这意味着,最初 John 将具有 nil 值,它将被设置并且一旦设置将永远不会再次被 nil 引导。因此,为了方便起见,我可以使用更简单的语法来访问可选 var,因为这是一个“隐式展开的可选”

    【讨论】:

    【解决方案9】:

    如果你来自 C 系列语言,你会想“指向 X 类型对象的指针,它可能是内存地址 0 (NULL)”,如果你来自动态类型语言,你'会想“可能是 X 类型但可能是未定义类型的对象”。这两个实际上都不正确,尽管第一个很接近。

    你应该把它想象成一个像这样的对象:

    struct Optional<T> {
       var isNil:Boolean
       var realObject:T
    }
    

    当您使用foo == nil 测试您的可选值时,它实际上返回了foo.isNil,而当您说foo! 时,它返回了foo.realObject,并带有foo.isNil == false 的断言。请务必注意这一点,因为如果 foo 在您执行 foo! 时实际上为 nil,则这是一个运行时错误,因此通常您希望使用条件 let 来代替,除非您非常确定该值不会为 nil。这种诡计意味着可以对语言进行强类型化,而无需强制您测试值是否到处都是 nil。

    在实践中,它并没有真正表现得像那样,因为工作是由编译器完成的。在高层次上,有一个类型 Foo?Foo 是分开的,它可以防止接受类型 Foo 的函数接收 nil 值,但在低层次上,可选值不是真正的对象,因为它没有属性或方法;实际上它很可能是一个指针,在强制展开时可以通过适当的测试为 NULL(0)。

    在其他情况下,您会在类型上看到感叹号,例如:

    func foo(bar: String!) {
        print(bar)
    }
    

    这大致相当于接受带有强制展开的可选,即:

    func foo(bar: String?) {
        print(bar!)
    }
    

    您可以使用它来拥有一个在技术上接受可选值但如果它为 nil 将产生运行时错误的方法。在当前版本的 Swift 中,这显然绕过了 is-not-nil 断言,因此您将遇到低级错误。通常不是一个好主意,但在从另一种语言转换代码时会很有用。

    【讨论】:

      【解决方案10】:

      !意味着您正在强制解开对象!跟随。更多信息可以在 Apples 文档中找到,可以在这里找到:https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/TheBasics.html

      【讨论】:

        【解决方案11】:

        如果您熟悉 C#,这类似于 Nullable 类型,也使用问号声明:

        Person? thisPerson;
        

        而且这种情况下的感叹号相当于像这样访问可空类型的.Value属性:

        thisPerson.Value
        

        【讨论】:

          【解决方案12】:

          在目标 C 中,没有值的变量等于 'nil'(也可以使用与 0 和 false 相同的 'nil' 值),因此可以在条件语句中使用变量(具有值的变量相同为 'TRUE',没有值的为 'FALSE')。

          Swift 通过提供“可选值”来提供类型安全。即它可以防止由于分配不同类型的变量而形成的错误。

          所以在 Swift 中,条件语句只能提供布尔值。

          var hw = "Hello World"
          

          这里,尽管 'hw' 是一个字符串,但它不能像在目标 C 中那样在 if 语句中使用。

          //This is an error
          
          if hw
          
           {..}
          

          为此,它需要创建为,

          var nhw : String? = "Hello World"
          
          //This is correct
          
          if nhw
          
           {..}
          

          【讨论】:

            【解决方案13】:

            !在对象的末尾表示该对象是可选的,如果它可以返回 nil,则展开。这通常用于捕获可能导致程序崩溃的错误。

            【讨论】:

              【解决方案14】:

              简而言之(!): 在您声明了一个变量并且您确定该变量包含一个值之后。

              let assumedString: String! = "Some message..."
              let implicitString: String = assumedString
              

              否则,您必须在每次传递值后都执行此操作...

              let possibleString: String? = "An optional string."
              let forcedString: String = possibleString! // requires an exclamation mark
              

              【讨论】:

                【解决方案15】:

                John 是一个可选的 Person,这意味着它可以保存一个值或为零。

                john.apartment = number73
                
                如果 john 不是可选的,则使用

                。由于 john 永远不会是 nil,我们可以确定它不会以 nil 值调用公寓。而

                john!.apartment = number73
                

                向编译器承诺 john 不是 nil,然后打开可选项以获取 john 的值并访问 john 的公寓属性。如果您知道 john 不是 nil,请使用此选项。如果你在 nil 可选参数上调用它,你会得到一个运行时错误。

                文档包含一个很好的示例,用于在 convertNumber 是可选的情况下使用它。

                if convertedNumber {
                    println("\(possibleNumber) has an integer value of \(convertedNumber!)")
                } else {
                    println("\(possibleNumber) could not be converted to an integer")
                }
                

                【讨论】:

                • 你是说如果 john 是 nil,而我去john.apartment = number73,除非我输入“!”,否则不会导致错误在约翰之后?
                • 如果 john 是可选的,则必须使用感叹号来访问其属性,因为编译器必须知道它不是 nil。如果它不是可选的,则不能使用感叹号。
                • 如果我必须对所有可选变量使用感叹号,那么 Apple 为什么还要费心呢,而不是让它缺少 感叹号意味着一样?这似乎是不必要的膨胀......或者是否存在不使用带有可选 var 的感叹号的情况?
                • 当您需要可选项不为零时使用感叹号。就像访问 john 的属性的情况一样。你可以做类似 var jack: Person? = john 其中 jack 也是可选的或 var jack:Person = john!其中杰克是一个人,不是零
                • 对,但是在原始示例中,我取消引用 john 可选的事实不是告诉编译器我需要它是非零的吗?...在​​你的var jack: Person = john! 例子,不是缺少一个吗?在 Person 告诉编译器您需要 john 非零之后?总的来说,! 似乎有点多余......我仍然觉得我在! 的“为什么”部分遗漏了一些东西......
                【解决方案16】:

                简单地说,感叹号意味着一个可选的被解包。可选项是可以有值或没有值的变量——因此您可以使用 if let 语句as shown here 检查变量是否为空,然后强制解包。如果你强制解开一个空的可选选项,你的程序会崩溃,所以要小心!可选项是通过在显式赋值给变量的末尾加上问号来声明的,例如我可以这样写:

                var optionalExample: String?
                

                这个变量没有值。如果我打开它,程序会崩溃,Xcode 会告诉你你试图打开一个值为 nil 的可选项。

                希望有所帮助。

                【讨论】:

                  【解决方案17】:

                  简单的话

                  使用感叹号表示变量必须包含非零值(它永远不会是零)

                  【讨论】:

                    【解决方案18】:

                    整个故事从 swift 的一个特性开始,称为可选变量。 这些是可能有值或可能没有值的变量。一般来说,swift不允许我们使用未初始化的变量,因为这可能会导致崩溃或意外原因,并且还会为后门提供占位符。 因此,为了声明一个初始值未确定的变量,我们使用“?”。 当声明这样的变量时,要将其用作某些表达式的一部分,必须在使用前对其进行解包,解包是一种操作,通过该操作可以发现变量的值,这适用于对象。如果您尝试使用它们而不打开包装,您将遇到编译时错误。 要解开作为可选 var 的变量,请使用感叹号“!”用来。

                    现在有时您知道此类可选变量将由系统(例如)或您自己的程序分配值,但稍后的某个时间,例如 UI 出口,在这种情况下,而不是使用问号声明可选变量“? "我们使用“!”。

                    因此系统知道这个用“!”声明的变量现在是可选的,没有价值,但会在其生命周期的后期收到一个价值。

                    因此感叹号有两种不同的用法, 1. 声明一个变量,该变量是可选的,以后肯定会收到值 2. 在表达式中使用可选变量之前解包它。

                    我希望以上描述避免了太多技术性内容。

                    【讨论】:

                      【解决方案19】:

                      如果您将其用作可选内容,它会打开可选内容并查看是否存在某些内容。如果你在 if-else 语句中使用它是 NOT 的代码。例如,

                      if (myNumber != 3){
                       // if myNumber is NOT 3 do whatever is inside these brackets.
                      )
                      

                      【讨论】:

                        【解决方案20】:

                        可选变量可能包含值,也可能不包含值

                        案例一:var myVar:String? = "Something"

                        案例2:var myVar:String? = nil

                        现在如果你问 myVar!,你是在告诉编译器返回一个值,如果 1 它将返回 "Something"

                        情况 2 会崩溃。

                        意义!标记将强制编译器返回一个值,即使它不存在。这就是名称强制展开的原因。

                        【讨论】:

                        • @Moritz。我不知道是这样吗?如果问题已经回答,我不能回答吗?我是否造成任何问题或我的回答有什么问题?我不明白你为什么不赞成正确回答它?我试图根据我对这个概念的理解来回答。我想有些人会发现它有助于清晰和简单的解释。
                        • @Moritz 现在这是建设性的。如果是这个原因,你应该首先告诉我这个更正。感谢您的反馈。我已经更正了。
                        【解决方案21】:

                        对于 Google 员工:

                        john!.department
                        

                        ...告诉编译器:

                        • 我知道john 是可选的
                        • 像有价值一样使用它
                        • 不崩溃就崩溃

                        在生产中,使用guard letif let来处理无值和无效硬崩溃的情况。

                        【讨论】:

                          【解决方案22】:
                          Simple the Optional variable allows nil to be stored.
                          
                          var str : String? = nil
                          
                          str = "Data"
                          
                          To convert Optional to the Specific DataType, We unwrap the variable using the keyword "!"
                          
                          func get(message : String){
                             return
                          }
                          
                          get(message : str!)  // Unwapped to pass as String
                          

                          【讨论】:

                          • 请不要写没有添加任何以前答案尚未涵盖的内容的答案。
                          【解决方案23】:

                          问问自己

                          • person? 类型是否有 apartment 成员/属性?或
                          • person 类型是否有 apartment 成员/属性?

                          如果你不能回答这个问题,那么继续阅读:

                          要了解您可能需要对泛型有超基本的了解。见here。 Swift 中的很多东西都是使用泛型编写的。包括选项

                          下面的代码已从this Stanford video 获得。强烈建议您观看前 5 分钟

                          一个 Optional 是一个只有 2 个案例的枚举

                          enum Optional<T>{
                              case None
                              case Some(T)
                          }
                          
                          let x: String? = nil //actually means:
                          
                          let x = Optional<String>.None
                          

                          let x :String? = "hello" //actually means:
                          
                          let x = Optional<String>.Some("hello")
                          

                          var y = x! // actually means:
                          
                          switch x {
                          case .Some(let value): y = value
                          case .None: // Raise an exception
                          }
                          

                          可选绑定:

                          let x:String? = something
                          if let y = x {
                              // do something with y
                          }
                          //Actually means:
                          
                          switch x{
                          case .Some(let y): print)(y) // or whatever else you like using 
                          case .None: break
                          }
                          

                          当你说var john: Person?时,你的意思实际上是这样的:

                          enum Optional<Person>{
                          case .None
                          case .Some(Person)
                          }
                          

                          上述枚举是否有任何名为apartment属性?你在任何地方看到它吗?它根本就在那里!但是,如果您打开它,即执行person!,那么您可以......它在引擎盖下的作用是:Optional&lt;Person&gt;.Some(Person(name: "John Appleseed"))


                          如果您定义了var john: Person 而不是:var john: Person?,那么您将不再需要使用!,因为Person 本身确实有apartment 的成员


                          关于为什么有时不建议使用! 解包的未来讨论,请参阅this Q&A

                          【讨论】:

                          • 使用上面的实际幻灯片可能侵犯版权:“...斯坦福大学确实保留我们 iTunes U 合集中所有内容的版权。”,来自http://itunes.stanford.edu。用您自己的话来说,可能更好地回答您从课程中学到的内容,您认为可以回答这个问题(而不是使用幻灯片,而是以代码形式引用它们的相关部分,用参考,自然)。
                          • 你的论点是argumentum ad populum。无论如何,I don't believe Stanford will come here and enforce DMCA rights,但如果你的答案是用你自己的话基于官方/有效来源,而不是像上面那样直接复制这些来源,那就更好了;特别是当我们谈论受版权保护的幻灯片时:再次,最好在代码块中引用幻灯片的内容(代码图像在 SO 中通常是禁忌!)。
                          • 我链接到的元帖子只是描述了 SO:s 的处理方法:如果一些随机用户将其报告为侵犯版权,自然不会删除这样的帖子:仅当例如斯坦福代表。来到这里,因为要删除的帖子将因此需要强制执行。因此我写了我不相信斯坦福会来这里执行 DMCA 权利,...”。我上面的观点是,我认为这可能是侵犯版权(我认为这是错误的),但自然没有人会强制执行。 ...
                          • 但除此之外,出于多种原因,发布包含代码图像的问题或答案是upright discouraged。总结一下:由于两个主要原因(受版权保护的幻灯片,代码图像),我试图用这些 cmets 指出我相信这个答案,以其目前的形式,并不完全像它可能的那样好。当然,包括我自己在内的任何人都不会对此做任何事情,我只是将其指向我们以供将来参考(或者可能鼓励您使用代码块引用来编辑这篇文章)。同意,iTunes U! :)
                          • @dfri 删除了图片
                          猜你喜欢
                          • 2011-01-11
                          • 1970-01-01
                          • 2021-09-18
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2010-11-02
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多