Syntax A';罗塞塔石';对于Swift&x27;什么是可选类型?

Syntax A';罗塞塔石';对于Swift&x27;什么是可选类型?,syntax,swift,semantics,optional,Syntax,Swift,Semantics,Optional,我掌握(我认为)基本知识,并大致了解?和之间的区别,但我仍然对我使用这些功能时得到的一些结果感到困惑——特别是some的作用,以及它与本身的区别;我在某些情况下收到的一些特定错误消息;在我预期的情况下,一些似乎会突然出现 但我也觉得,即使我理解了个别案例,我对图片的理解也离我越来越远,我觉得这里有一个代码,只要我完全理解了一个简单的例子,我就可以破译它——如果你愿意的话,罗塞塔石——for、?、可选值和解包 例如,这里有一个简单且(我认为)详尽的基本案例目录: class Foo { v

我掌握(我认为)基本知识,并大致了解
之间的区别
,但我仍然对我使用这些功能时得到的一些结果感到困惑——特别是
some
的作用,以及它与
本身的区别;我在某些情况下收到的一些特定错误消息;在我预期的情况下,一些似乎会突然出现

但我也觉得,即使我理解了个别案例,我对图片的理解也离我越来越远,我觉得这里有一个代码,只要我完全理解了一个简单的例子,我就可以破译它——如果你愿意的话,罗塞塔石——for
、可选值和解包

例如,这里有一个简单且(我认为)详尽的基本案例目录:

class Foo {
    var one:String = "";
    var two:String?
    var three:String!
}

let test = Foo()        // {one "" nil nil}

test.one
//test.one?             //  ERROR: ? requires optional type
//test.one!             //  ERROR: ! requires optional type

// ?, unassigned
test.two                // nil
test.two?               // nil
//test.two!             // ERROR: EXEC_BAD_INSTRUCTION

test.two == nil         // true
test.two? == nil        // true
//test.two! == nil      // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)

//test.two.isEmpty      // ERROR: String? does not have .isEmpty
test.two?.isEmpty       // nil
//test.two!.isEmpty     // ERROR: EXEC_BAD_INSTRUCTION

// !, unassigned
test.three              // nil
test.three?             // nil
//test.three!           // ERROR: EXEC_BAD_INSTRUCTION

test.three == nil       // true
test.three? == nil      // true
//test.three! == nil    // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)

//test.three.isEmpty    // ERROR: EXEC_BAD_INSTRUCTION
test.three?.isEmpty     // nil
//test.three!.isEmpty   // ERROR: EXEC_BAD_INSTRUCTION


test.two = "???"        // {one "" {Some "???"} nil}
test.three = "!!!"      // {one "" {Some "???"} three "!!!"}

// ?, assigned
test.two                // {Some "???"}
test.two?               // {Some "???"}
test.two!               // "???"

test.two == nil         // false
test.two? == nil        // false
//test.two! == nil      // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)

//test.two.isEmpty      // ERROR: String? does not have .isEmpty
test.two?.isEmpty       // {Some false}
test.two!.isEmpty       // false

// !, assigned
test.three              // "!!!"
test.three?             // {Some "!!!"}
test.three!             // "!!!"

test.three == nil       // false
test.three? == nil      // false
//test.three! == nil    // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)

test.three.isEmpty      // false
test.three?.isEmpty     // {Some false}
test.three!.isEmpty     // false

如果有人能对此进行注释,解释每种情况下的情况,我认为这个答案可以作为Swift这些功能如何工作的可靠参考。

好的,我将尝试回答所有这些问题。可能没有领带来解决所有问题:

注意:如果有错误,请随时给我打电话。这需要一段时间,所以我确实做了一些

快速说明:
可选
实际上是一个枚举。它有两种状态:
.None
.Some(T)
,其中
T
是值的类型(在您的示例中为
String

Foo
有一个名为
one
的属性,该属性返回一个
字符串。一个明确的
字符串
,不是可选的,这意味着它肯定会有一个值。您对待这一点的方式类似于在代码中编写
“HI!”
。这个值实际上是

这是一个错误,因为如上所述,
test.one
返回一个明确的
字符串,因此不可能为零。您可以保证返回值存在

//test.one!             //  ERROR: ! requires optional type
和那个一样?。这个是一个强制展开运算符,这意味着test.one可能为nil,但您仍希望强制输出该值(如果不存在,则崩溃)。但是,可能为零,因此您不能有一个?或者一个

test.two                // nil
test.two
是一个
字符串?
,可以为零。因为它是可选的,所以您可以像在代码中一样返回nil。它的实际值是
。无
,因此您看到的值实际上是一个字符串?不是一串

test.two?               // nil
test.three!             // "!!!"
这与上面的操作基本相同,只是您明确地说值可能是nil

//test.two!             // ERROR: EXEC_BAD_INSTRUCTION
您永远不能使用
nil
值上执行code>,而不希望它崩溃。当您使用此运算符时,它会强制输出一个值(因此您将拥有一个字符串,而不是字符串?)。但是,如果该值为nil,则没有要强制输出的值,因此最终会导致程序崩溃

test.two == nil         // true
test.two
as clear返回nil或.None(它们是等效的)。因此,如果比较
nil==nil
.None==.None
,则为真

test.two? == nil        // true
同上

//test.two! == nil      // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)
每次强制展开nil值都会使程序崩溃。这也没有意义,因为强制展开将返回
字符串,而不是
字符串?
<代码>字符串
不能为
nil

//test.two.isEmpty      // ERROR: String? does not have .isEmpty
test.three == nil       // true
test.three? == nil      // true
//test.three! == nil    // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)
基本上,每当您想对可选对象调用方法时,都需要使用可选绑定或可选链接(两个不同的东西)来确保它有一个值。一串等于Optional.Some(字符串),您需要通过可选层才能获得所需的字符串

test.two?.isEmpty       // nil
这里使用可选的链接。基本上,其工作方式是对
test.two
进行评估。如果该值是
.Some(String)
,则对该字符串调用
isEmpty
。否则,如果它是
.None
,则什么也不会发生。这些可选链可以在每个语句中出现多行,例如
test.two?.firstEmoji?
(假设实现了这样的方法)

//test.two!.isEmpty     // ERROR: EXEC_BAD_INSTRUCTION
同样,强制展开nil可选值是不好的。在未首先检查值是否确实为
。某些值为

test.three              // nil
由于
three
是隐式展开的,并且它被初始化为
nil
(通过不设置为其他值),因此这并不奇怪

test.three?             // nil
这不是您可能在实际代码中使用的东西,因为它本质上是可选的链接,但后面没有任何内容。但是,在这里,因为
。三个
隐式展开
具有“重新包装”的效果它:结果的类型现在是
String?
。这在这里没有什么区别,但是在
测试之后,看看下面它做了什么。三个
已经分配了一个
String

//test.three!           // ERROR: EXEC_BAD_INSTRUCTION
如上所述,无法展开
nil
。这可能会让人感到困惑,因为声明通常被描述为生成一个“隐式展开”的变量;但如果它不是
nil
,则应将其理解为“隐式展开”

与上面的2相同。如果您有一个强制展开变量,则?会显示为取消强制展开,这是我不建议的行为。尝试不经常使用强制展开选项,如果确实需要,主要与UI的某些部分有关。通常情况下,它会在您不期望的情况下崩溃

//test.three.isEmpty    // ERROR: EXEC_BAD_INSTRUCTION
test.three?.isEmpty     // nil
//test.three!.isEmpty   // ERROR: EXEC_BAD_INSTRUCTION
当一个可选的未赋值时,它默认为nil。如果你尝试强制展开它…我想你明白了。第一行和第三行尝试从nil上的字符串调用一个方法(适用于ObjC,而不是Swift)。第二行使用可选链接在调用方法之前检查它是否为nil,因为它知道它是nil,所以不能这样做

test.two = "???"        // {one "" {Some "???"} nil}
test.three = "!!!"      // {one "" {Some "???"} three "!!!"}
这将设置
测试。两个
等于
。一些(“?”)
测试。三个
等于
。一些(!!!)
输出
test.two = "???"        // {one "" {Some "???"} nil}
test.three = "!!!"      // {one "" {Some "???"} three "!!!"}
test.two                // {Some "???"}
test.two?               // {Some "???"}
test.two!               // "???"
test.two == nil         // false
test.two? == nil        // false
//test.two! == nil      // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)
//test.two.isEmpty      // ERROR: String? does not have .isEmpty
test.two?.isEmpty       // {Some false}
test.two!.isEmpty       // false
test.three              // "!!!"
test.three?             // {Some "!!!"}
test.three!             // "!!!"
test.three == nil       // false
test.three? == nil      // false
//test.three! == nil    // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)
test.three.isEmpty      // false
test.three?.isEmpty     // {Some false}
test.three!.isEmpty     // false