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- firstInt
和firstInt
会导致崩溃,如下所示: