我掌握(我认为)optional types in Swift的基础知识,粗略地理解?
和!
之间的区别,但我仍然对我得到的一些结果感到困惑使用这些功能 - 特别是Some <T>
的作用,以及它与<T>
本身的区别;我在某些情况下得到的一些特定错误消息;以及在我期望Some <T>
的情况下,<T>
似乎如何弹出。
但我也觉得,即使我理解个别情况,我对图片的掌握也远离我,我觉得这里有一个代码,如果我完全理解一个简单示例 - 如果您愿意,可以使用Rosetta Stone - !
,?
,可选值和解包。
例如,这里是一个简单的(我认为)基本案例的详尽目录:
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的这些功能如何运作的可靠参考。
答案 0 :(得分:4)
好吧,我将尝试回答这一切。可能没有领带来完成所有事情:
注意:如有错误,请随时与我联系。这需要一段时间,所以我肯定做了一些。
快速说明:Optional
实际上是一个枚举。它有两种状态:.None
和.Some(T)
,其中T
是值的类型(在您的情况下为String
)。
test.one
Foo
有一个名为one
的属性,返回String
。一个明确的String
,而不是一个可选的,意味着它肯定有一个值。您对此的处理方式与在代码中编写"HI!"
的方式类似。这个值实际上是""
//test.one? // ERROR: ? requires optional type
这是一个错误,因为如上所述,test.one
会返回一个明确的String
,因此它不可能是零。您可以保证返回值存在。
//test.one! // ERROR: ! requires optional type
与?相同。的!是一个强制解包运算符,意味着有一个机会 test.one可能是nil,但是你想要强制取出值(如果不是则崩溃)那里)。但是,没有机会它是零,所以你不能拥有?还是一个!。
test.two // nil
test.two
是String?
,可以为零。因为它是可选的,所以允许您像在代码中一样返回nil。这个的真正价值是.None
,所以你看到的值实际上是一个字符串?不是字符串。
test.two? // nil
这基本上与上面的相同,除非您明确说明该值可能为零。
//test.two! // ERROR: EXEC_BAD_INSTRUCTION
您永远不能在!
值上使用nil
而不会让它崩溃。当你使用这个操作符时,它会强制一个值(所以你有一个String,而不是String?)。但是,如果值为nil,则强制输出 no 值,因此最终导致程序崩溃。
test.two == nil // true
test.two
显然返回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值每次都会使程序崩溃。它也没有意义,因为强制解包会返回String
,而不是String?
。 String
不能是nil
。
//test.two.isEmpty // ERROR: String? does not have .isEmpty
基本上,无论何时想要在可选项上调用方法,都需要使用可选绑定或可选链接(两个单独的东西)确保它具有值。串?等于Optional.Some(String),你需要通过可选层来获得你想要的字符串。
test.two?.isEmpty // nil
这里使用可选链接。基本上,这种方式的工作方式是test.two
被评估。如果值为.Some(String)
,则在字符串上调用isEmpty
。否则,如果是.None
,则没有任何反应。这些可选链可以在每个语句中出现多行,例如test.two?.firstEmoji?
(假设已经实现了这样的方法。
//test.two!.isEmpty // ERROR: EXEC_BAD_INSTRUCTION
同样,强制展开零选项是不好的。如果没有先检查该值是否为.Some
,请不要这样做。
test.three // nil
由于three
被隐式展开,并且它已初始化为nil
(未被设置为其他内容),因此这不应该令人惊讶。
test.three? // nil
这不是你可能在实际代码中使用的东西,因为它本质上是可选的链接,但在它之后没有任何东西。但是在这里,由于.three
被隐式展开?
具有&#34;重新包装&#34;它:结果的类型现在是String?
。这在这里没什么区别,但是在test.three
分配了String
值之后,请查看下面的内容。
//test.three! // ERROR: EXEC_BAD_INSTRUCTION
如上所述无法解开nil
。这可能看起来令人困惑,因为声明通常被描述为产生一个隐含地展开的变量&#34 ;;但是如果它不是 nil
&#34;那么它应该被理解为&#34;隐式解包。
test.three == nil // true
test.three? == nil // true
//test.three! == nil // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)
与上述2相同。如果你有一个强制解包的变量,一个?似乎没有强行打开它,这是我不建议的行为。尝试不经常使用强制解包的选项,如果你真的需要,主要是与部分UI有关。很多时候,当你不期待它时它会崩溃。
//test.three.isEmpty // ERROR: EXEC_BAD_INSTRUCTION
test.three?.isEmpty // nil
//test.three!.isEmpty // ERROR: EXEC_BAD_INSTRUCTION
如果未指定可选项,则默认为nil。如果你然后试着强行打开它...我想你明白了。第一行和第三行尝试从nil上的String调用方法(在ObjC中工作,而不是Swift)。第二个使用可选链接在调用方法之前检查它是否为零,因为它知道它是零,所以它不能。
test.two = "???" // {one "" {Some "???"} nil}
test.three = "!!!" // {one "" {Some "???"} three "!!!"}
这会将test.two
设为.Some("???")
,test.three
等于.Some("!!!")
您看到的输出只会显示该类中保存的所有变量,以及它们的变化方式。< / p>
test.two // {Some "???"}
test.two? // {Some "???"}
test.two! // "???"
test.two
现在是.Some("???")
,所以当你调用它时,返回的是:一个字符串?有价值的。强制解包时,它现在返回.Some
中保存的值而不会崩溃,因为其中确实存在一个字符串。
test.two == nil // false
test.two? == nil // false
test.two
仍然是可选的,所以在前两个中,当它将它们与nil进行比较时,它意识到,&#34;嘿,有.Some值,所以不是 nil。&#34;
//test.two! == nil // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)
强制解包值会从字符串中转换test.two
的值?到一个字符串。字符串永远不会是零,因为如果它们是,它们将需要是可选的。将一个绝对是String的值与nil进行比较是没有意义的,因为你知道一个事实它不是nil;否则,程序会崩溃之前!
//test.two.isEmpty // ERROR: String? does not have .isEmpty
test.two
是String ?,而不是String。为了访问字符串本身,您需要确保它可以访问,使用?还是一个!
test.two?.isEmpty // {Some false}
这说,&#34;如果test.two
包含一个字符串(不是nil),则查找它是否为空。&#34;它说{Some false}
因为你正在访问一个Optional的成员,而不是一个直接的String。
test.two!.isEmpty // false
!,另一方面, 返回一个字符串。在字符串上调用.isEmpty
可以是true
或false
,在这种情况下是false
,因为您将其设置为非空字符串。
test.three // "!!!"
test.three
强制 - 从中解包String,在这种情况下,因为它有一个值,所以它可以工作。
test.three? // {Some "!!!"}
您将此视为普通可选(不强制解包),因此您获得的是Some(String)而不仅仅是String。
test.three! // "!!!"
由于你在声明中强行打开它,所以它在这里被强行打开。
test.three == nil // false
这是另一种奇怪的行为,因为它应该是一个错误。它应该是一个String,无法与nil进行比较,但这里有一些古怪的东西。当我发现这件事时,我会回复你。
test.three? == nil // false
将test.three
视为普通可选项,并检查其状态是.None
还是无。
//test.three! == nil // ERROR: Cannot invoke == with an argument list of type (@lvalue String, NilLiteralConvertable)
上面的那两个应该是什么样的。无法将String与nil进行比较,因此会抛出错误。
test.three.isEmpty // false
查看被强制输出的字符串值(存在;否则,它会崩溃)。该字符串不为空,因此它是错误的。
test.three?.isEmpty // {Some false}
将其视为字符串?如果test.three
不是nil,则它从.Some(一个String)获取值,并计算它是否为空,而不是。
test.three!.isEmpty // false
String被强制退出可选项,isEmpty直接调用它。它不是空的,因此返回false。
我希望我能帮助澄清事情,我会告诉你为什么一个案例就是我自己找到的方式:]