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 的语言很陌生.只是想把基本的东西记下来.


UPDATE:
The big piece of the puzzle that I was missing (not directly stated in the answers - at least not at the time of writing this) is that when you do the following:

var john: Person?

这并不意味着"johnPerson型,可能是零",正如我最初所想.我只是误解了PersonPerson?是完全不同的类型.一旦我明白了这一点,所有其他的?!疯狂,以及下面伟大的答案,都变得更有意义.

推荐答案

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

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

"包装"一词意味着我们应该think of an Optional variable as a present, wrapped in shiny paper, which might (sadly!) be empty.

"包装"时,可选变量的值是一个包含两个可能值(有点像布尔值)的枚举.此枚举描述变量是否包含值(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值可以通过多种方式展开:

  • "强制展开":john!(如果存在,则给出Person值;如果为零,则给出运行时错误)
  • "可选绑定":if let p = john { println(p) }(如果该值存在,则执行println)
  • "可选链接":john?.learnAboutSwift()(如果该值存在,则执行此组合方法)

我猜你会 Select 这些方法中的一种来展开,这取决于在零的情况下会发生什么,以及可能性有多大.这种语言设计强制显式处理nil情况,我认为这提高了Obj-C的安全性(在Obj-C中很容易忘记处理nil情况).

Update:

感叹号也用于声明"隐式展开选项"的语法中.

在到目前为止的示例中,john变量被声明为var john:Person?,它是可选的.如果需要该变量的实际值,必须使用上述三种方法之一将其展开.

如果将其声明为var john:Person!,则该变量将是一个隐式展开的可选变量(请参阅Apple书中带有此标题的部分).在访问该值时,不需要展开此类变量,并且可以在不使用其他语法的情况下使用john.但苹果的书上说:

当一个变量可能在以后变为零时,不应使用隐式展开选项.如果需要在变量的生命周期内判断nil值,请始终使用普通可选类型.

Update 2:

Mike Ash的文章"Interesting Swift Features"为可选类型提供了一些动力.我认为这是一篇很棒的、清晰的文章.

Update 3:

另一篇关于感叹号implicitly unwrapped optional用法的有用文章是Chris Adamson写的:"Swift and the Last Mile".这篇文章解释说,这是苹果用来声明Objective-C框架使用的类型的一种实用方法,这些框架可能包含nil.将类型声明为可选(使用?)或隐式展开(使用!)是"安全性和方便性之间的权衡".在本文给出的示例中,Apple Select 将类型声明为隐式展开,这使得调用代码更方便,但安全性更低.

也许苹果将来可能会梳理它们的框架,消除隐式展开("可能永远不会为零")参数的不确定性,并用可选参数("当然可能为零,尤其是[希望有记录的!]根据其Objective-C代码的确切行为,环境)或标准非可选("从不为零")声明.

Swift相关问答推荐

如何避免使用DispatchSemaphores时线程爆炸?

为什么我的引用类型对象在初始化后有3个强引用?

纹理资源加载问题(图像解码失败)

MacOS 13-如何使用SwiftUI创建Message.App设置工具栏?

在扩展中创建通用排序函数

为什么Swift可以在没有足够信息的情况下推断类型?

将弱引用作为类函数引用传递时,弱引用无法按预期工作

使第二个视图变灰 SwiftUI

swiftui中服务端图片如何设计view并赋予rotationEffect?

一组可散列的自定义元素插入相等的元素

我如何遵守与演员的协议?

Pod lib lint 命令找不到 watchos 模拟器

并发执行代码中捕获的 var 的变异

如何从数据中读取以空结尾的字符串?

在 SwiftUI 中,如何在 UIView 内或作为 UIView 使用 UIHostingController?

Swift 3.0 的 stringByReplacingOccurencesOfString()

CMutablePointer - 如何访问它?

如何快速识别字符串中的大写和小写字符?

<<错误类型>> 奇怪的错误

使用 swift IOS 使 UIBarButtonItem 消失