Swift编程语言指南中有如下示例:
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?
这并不意味着“约翰是人的类型,它可能是nil”,因为我最初的想法。我只是误解了《人与人》是完全不同的类型。一旦我明白了,所有其他的?,!疯狂,以及下面这些精彩的回答,让我觉得更有道理。
如果你来自c语言家族,你会想“指向X类型对象的指针,它可能是内存地址0 (NULL)”,如果你来自动态类型语言,你会想“对象可能是X类型,但可能是未定义的类型”。这两种说法实际上都不正确,尽管迂回地说,第一个说法很接近。
你应该把它想象成一个物体:
struct Optional<T> {
var isNil:Boolean
var realObject:T
}
When you're testing your optional value with foo == nil it's really returning foo.isNil, and when you say foo! it's returning foo.realObject with an assertion that foo.isNil == false. It's important to note this because if foo actually is nil when you do foo!, that's a runtime error, so typically you'd want to use a conditional let instead unless you are very sure that the value will not be nil. This kind of trickery means that the language can be strongly typed without forcing you to test if values are nil everywhere.
实际上,它并不是这样做的,因为工作是由编译器完成的。在高层次上有一个类型Foo?它与Foo是分开的,这可以防止接受类型Foo的函数函数接收到nil值,但在低级别上,可选值不是一个true对象,因为它没有属性或方法;实际上,它很可能是一个指针,在强制展开时,通过适当的测试,它可能是NULL(0)。
还有一种情况,你会看到感叹号是在一种类型上,比如:
func foo(bar: String!) {
print(bar)
}
这大致相当于接受一个强制展开的可选选项,即:
func foo(bar: String?) {
print(bar!)
}
你可以使用它来创建一个方法,该方法在技术上接受一个可选值,但如果它为nil,则会出现运行时错误。在当前版本的Swift中,这显然绕过了is-not-nil断言,所以你会有一个低级错误。通常不是个好主意,但在从另一种语言转换代码时可能很有用。
在objective C中,没有值的变量等于“nil”(也可以使用与0和false相同的“nil”值),因此可以在条件语句中使用变量(有值的变量与“TRUE”相同,而那些没有值的变量等于“false”)。
Swift通过提供“可选值”来提供类型安全。即,它可以防止因分配不同类型的变量而形成错误。
所以在Swift中,只有条件语句可以提供布尔值。
var hw = "Hello World"
这里,虽然'hw'是一个字符串,但它不能像objective - C那样在if语句中使用。
//This is an error
if hw
{..}
为此,它需要被创建为,
var nhw : String? = "Hello World"
//This is correct
if nhw
{..}
The entire story begins with a feature of swift called optional vars.
These are the vars which may have a value or may not have a value. In general swift doesn't allow us to use a variable which isn't initialised, as this may lead to crashes or unexpected reasons and also server a placeholder for backdoors.
Thus in order to declare a variable whose value isn't initially determined we use a '?'.
When such a variable is declared, to use it as a part of some expression one has to unwrap them before use, unwrapping is an operation through which value of a variable is discovered this applies to objects. Without unwrapping if you try to use them you will have compile time error.
To unwrap a variable which is an optional var, exclamation mark "!" is used.
有时候你知道这样的可选变量会被系统或者你自己的程序赋值,但是稍后,比如UI outlet,在这种情况下,我们不会用问号"?"来声明可选变量,而是用"!"
因此,系统知道这个用“!”声明的变量现在是可选的,没有值,但将在其生命周期的后期接收一个值。
因此,感叹号有两种不同的用法,
1. 声明一个变量,该变量将是可选的,并且以后一定会接收值
2. 在表达式中使用可选变量之前,将其展开。
以上描述避免了太多的技术问题,我希望。