string有什么区别? 和弦乐! (两种创build可选variables的方法)?

Swift编程语言 (苹果书)中,我读过你可以用两种方法创build可选variables:使用问号(?)或使用感叹号(!)。

不同之处在于,当你使用(?)得到一个可选值时,每次需要该值时都必须使用感叹号:

var str: String? = "Question mark?" println(str!) // Exclamation mark needed str = nil 

而用(!)你可以得到它没有后缀:

 var str: String! = "Exclamation mark!" println(str) // No suffix needed str = nil 

有什么区别,为什么有两种方式,如果没有任何区别?

使用隐式解包选项(使用!声明)的真正好处与两个类相互指向时的类初始化相关,并且您需要避免强引用循环。 例如:

A类< – > B类

A类的初始化例程需要创build(并拥有)B类,而B需要一个弱引用返回给A:

 class A { let instanceOfB: B! init() { self.instanceOfB = B(instanceOfA: self) } } class B { unowned let instanceOfA: A init(instanceOfA: A) { self.instanceOfA = instanceOfA } } 

现在,

  • B类需要对A类的引用进行初始化。
  • 一旦完全初始化,A类只能将self传递给B类的初始化者。
  • 对于在创build类B之前被认为是初始化的类A,属性instanceOfB因此必须是可选的。

但是,一旦创build了A,就不得不使用instanceOfB访问instanceOfB! 因为我们知道必须有一个B

为了避免这种情况,instanceOfB被声明为一个隐含的可选的(instanceOfB!),我们可以使用instanceOfB来访问它。 (此外,我怀疑编译器也可以不同地优化访问)。

本书的第464至466页给出了一个例子。

概要:

  • 使用 ? 如果价值在将来可能成为零,那么你为此进行testing。
  • 使用 ! 如果未来真的不应该成为零,但最初还是零。

你应该超越语法糖。

有两种完全不同的多态types。 语法糖只是使用这些types中的一个或另一个。

当你写Foo? 作为一个types,你真的有Optional<Foo> ,而当你写Foo! 你真的有ImplicitlyUnwrappedOptional<Foo>

这是两种不同的types,它们也不同于Foo

String! kind被称为隐式解包可选

有时候从程序的结构中可以清楚地看到,在第一次设置值之后,可选项总是有一个值。 在这些情况下,每次访问时都不需要检查和打开可选的值,因为可以安全地假定所有的时间都有一个值。

这些选项被定义为隐含的解包选项。 你写一个隐式解开的可选项,在你想要的可选types之后放置一个感叹号(String!)而不是一个问号(String?)。

您创build的值? 是你提到的普通的可选值,你应该通过可选的绑定( if let unwrappedValue = myOptionalValue )或使用感叹号语法myOptionalValue!.doSomething()

您创build的值! 被称为隐式unwrapped选项。 有了它们,在使用它们之前不需要手动拆包。 当你做val myOptionalValue!.doSomething()

当你直接使用myOptionalValue时候,这个值会被自动解包出来,不过要小心,因为当它实际上没有任何值的时候(当它是nil )访问一个隐式地解开的值将会导致运行时错误。

在可选的链接部分,您可以find答案:

示例类:

 class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } 

如果您尝试访问此人的住所的numberOfRooms属性,在居住之后放置感叹号以强制展开其值,则会触发运行时错误,因为没有居住值可以解开:

 let roomCount = john.residence!.numberOfRooms // this triggers a runtime error 

上面的代码在john.residence具有非零值时成功,并将roomCount设置为包含适当房间数的Int值。 但是,如上所示,此代码在居住时间为零时总是触发运行时错误。

可选的链接提供了另一种访问numberOfRooms值的方法。 要使用可选的链接,请使用问号代替感叹号:

 if let roomCount = john.residence?.numberOfRooms { println("John's residence has \(roomCount) room(s).") } else { println("Unable to retrieve the number of rooms.") } // prints "Unable to retrieve the number of rooms." 

上面提到@tarmes。 注意到隐式可选的另一个用法:

可以说我有一个可选的Int

 let firstInt: Int? = 9 

我试图使用可选的模式匹配,并使用这个可选的Int像这样:

 if case let myFirstInt? = firstInt where myFirstInt > 1 { print("Valid") } else { print("Invalid") } 

请注意,我使用隐式可选与本地参数myFirstInt使与可选的firstInt链接的firstInt 。 如果现在,我firstInt作为nil ,它会执行其他条件。 相反,如果我使用force- firstIntfirstInt会导致崩溃,如下所示:

在这里输入图像说明