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