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

感叹号在Swift语言中是什么意思?,swift,optional,forced-unwrapping,Swift,Optional,Forced Unwrapping,具有以下示例: 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.numbe

具有以下示例:

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
var john: Person?
我对斯威夫特语很陌生。只是想把基本的东西记下来


更新:
我遗漏的谜题的一个重要部分(答案中没有直接说明——至少在写这篇文章的时候没有)是当你做以下事情时:

john.apartment = number73
var john: Person?

这并不意味着“
john
属于
Person
类型,可能是nil”,正如我最初所想。我只是误解了
Person
Person?
是完全不同的类型。一旦我掌握了,所有其他的
疯狂和下面的精彩答案更有意义。

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

从文件

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

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


John是一个可选的人,这意味着它可以持有一个值或为零

john.apartment = number73
如果john不是可选项,则使用。因为john从不为零,所以我们可以确保它不会以零值调用公寓。而

john!.apartment = number73
向编译器承诺john不是nil,然后展开可选项以获取john的值并访问john的公寓属性。如果知道john不是nil,请使用此选项。如果对nil可选项调用此选项,则会出现运行时错误

文档中包含了一个很好的示例,其中convertedNumber是可选的

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

如果john是可选的var(如此声明)

那么约翰就有可能没有价值(用ObjC的说法,零价值)

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

if let otherPerson = john {
    otherPerson.apartment = number73
}
只有john有一个值时,才会对其内部进行评估

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

据我所知(这对我来说也是非常新鲜的)

术语“包装”意味着我们应该把一个可选变量当作礼物,用闪亮的纸包装,纸可能(很遗憾!)是空的

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

如果有值,可以通过“展开”变量(从
Some(T)
中获取
T
)来获得该值

john!.partment=number73
john.partment=number73
有何不同

如果您写入可选变量的名称(例如text
john
,而不包含
),则这指的是“包装”枚举(Some/None),而不是值本身(T)。因此
john
不是
Person
的实例,也没有
单元成员:

john.apartment
// 'Person?' does not have a member named 'apartment'
实际的
Person
值可以通过多种方式展开:

  • “强制展开”:
    john!
    (如果存在,则给出
    Person
    值,如果为零,则给出运行时错误)
  • “可选绑定”:
    if let p=john{println(p)}
    (如果值存在,则执行
    println
  • “可选链接”:
    john?.learnAboutSwift()
    (如果值存在,则执行此组合方法)
我猜您会选择其中一种方法来展开,这取决于nil情况下会发生什么以及可能性有多大。这种语言设计强制显式处理nil情况,我认为这会提高Obj-C的安全性(在Obj-C中很容易忘记处理nil情况)

更新

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

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

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

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

更新2

Mike Ash的文章“”为可选类型提供了一些动力。我认为这是一篇很棒、清晰的文章

更新3

另一篇关于感叹号的隐式展开可选用法的有用文章:“Chris Adamson。这篇文章解释说,这是Apple用于声明Objective-C框架使用的类型(可能包含零)的实用措施。将类型声明为可选(使用
)或隐式展开(使用
)是“安全和方便之间的权衡”。在本文给出的示例中,苹果选择将类型声明为i
john.apartment
// 'Person?' does not have a member named 'apartment'
var hw = "Hello World"
//This is an error

if hw

 {..}
var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}
var john: Person?
john?.apartment = number73
if john != nil {
    john.apartment = number73
}
john!.apartment = number73
john.apartment = number73
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."
var optionalExample: String?
var name:String = "Hello World"
var word:String?
word = name 
var cow:String = nil
var dog:String!
dog = cow
Person? thisPerson;
thisPerson.Value
let assumedString: String! = "Some message..."
let implicitString: String = assumedString
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
struct Optional<T> {
   var isNil:Boolean
   var realObject:T
}
func foo(bar: String!) {
    print(bar)
}
func foo(bar: String?) {
    print(bar!)
}
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
}
enum Optional<Person>{
case .None
case .Some(Person)
}
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
if (myNumber != 3){
 // if myNumber is NOT 3 do whatever is inside these brackets.
)