繁体   English   中英

String和有什么不一样? 和弦! (创建可选变量的两种方式)?

[英]What is the difference between String? and String! (two ways of creating an optional variable)?

《 Swift编程语言》 (Apple书)中,我读到可以用两种方式创建可选变量:使用问号(?)或使用感叹号(!)。

区别在于,当使用(?)获取可选值时,每次需要该值时都必须使用感叹号:

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

使用(!)时,您可以不带后缀:

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

有什么区别?如果根本没有区别,为什么有2种方法呢?

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

A级<-> B级

A类的初始化例程需要创建(并拥有)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类的初始化器。
  • 为了使类A在创建类B之前被视为已初始化,因此属性instanceOfB必须是可选的。

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

为了避免这种情况,instanceOfB被声明为一个隐式未包装的可选(instanceOfB!),我们可以仅使用instanceOfB对其进行访问。 (此外,我怀疑编译器也可以不同地优化访问)。

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

摘要:

  • 采用 ? 如果该值将来可能变为nil,以便对此进行测试。
  • 采用 ! 如果将来它真的不应该变为零,但是最初需要为零。

您应该超越语法糖。

有两种完全不同的多态类型。 语法糖仅使用这些类型中的一种或另一种。

当您写Foo? 作为类型,您实际上具有Optional<Foo> ,而在编写Foo! 您确实有ImplicitlyUnwrappedOptional<Foo>

这是两种不同的类型,它们也与Foo不同。

String! kind称为隐式展开的可选

有时,从程序的结构中可以明显看出,在首次设置可选值之后,该可选值将始终具有一个值。 在这些情况下,删除每次访问可选参数的值的必要性很有用,因为可以安全地假定它始终具有一个值。

这些类型的可选定义为隐式解包的可选。 您通过在要使其为可选的类型之后放置感叹号(String!)而不是问号(String?)来编写隐式解包的可选。

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

使用创建的值! 被称为隐式展开的可选。 使用它们,您无需在使用它们之前手动打开包装。 当您执行val myOptionalValue!.doSomething()

当您直接使用myOptionalValue时,该值将自动为您解包,但是请谨慎操作,因为在其中实际上没有任何值(当值为nil )时访问隐式解包的值将导致运行时错误。

(可选)表示您的变量可能包含nil值,而
(解包器)表示在运行时使用变量(尝试从中获取值)时,变量必须具有内存(或值)。

主要区别在于,当可选值为nil时,可选链接会正常失败,而当可选值为nil时,强制展开会触发运行时错误。

为了反映可以在nil值上调用可选链接的事实,即使要查询的属性,方法或下标返回非可选值,可选链接调用的结果也始终是可选值。 您可以使用此可选返回值来检查可选链接调用是否成功(返回的可选值包含一个值),或者由于链中的值为nil而失败(返回的可选值为nil)。

具体来说,可选链接调用的结果与预期返回值的类型相同,但包装在可选中。 通常返回Int的属性将返回Int? 通过可选链访问时。

var defaultNil : String?  // declared variable with default nil value
println(defaultNil) >> nil  

var canBeNil : String? = "test"
println(canBeNil) >> optional(test)

canBeNil = nil
println(canBeNil) >> nil

println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper

var canNotBeNil : String! = "test"
print(canNotBeNil) >> "test"


var cantBeNil : String = "test"
cantBeNil = nil // can't do this as it's not optional and show a compile time error

有关更多详细信息,请参阅Apple Developer Commitee的详细文档。

在可选的链接部分中,您会找到答案:

示例类:

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

如果尝试访问此人的住所的numberOfRooms属性,方法是在住所后放置一个感叹号以强制其值解开,从而触发运行时错误,因为没有要解开的住所值:

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

上面的代码在john.residence具有非nil值时成功,并将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隐式optional,使它对于与可选firstInt链接的nil条件是安全的。 如果现在,我将firstInt设为nil ,它将执行else条件。 相反,如果我对firstInt使用force- firstInt会导致崩溃,则如下所示:

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM