2014-10-02 64 views
3

我把握(我認爲)的optional types in Swift和連鰭鮭基本瞭解?!之間的差別,但我仍然通過一些結果我得到的困惑,當我使用這些功能 - 尤其是Some <T>的作用,以及如何它不同於<T>本身;某些特定的錯誤消息,我在某些情況下得到;以及Some <T>在我預期<T>的情況下似乎彈出。「Rosetta Stone」是Swift的可選類型嗎?

但我也覺得,即使我明白個別情況下,我的畫面的把握變得離我而去,而我覺得這裏有一個代碼,我可以破譯,如果只有我完全瞭解一個簡單的例子 - 一個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

注:我知道有很多的關於這個問題(和很多偉大的答案);我已經閱讀了所有內容。我在這裏尋找的東西有點不一樣:在一個簡單的例子的背景下,解釋規則如何在每個特定的情況下在一個地方展示出來。另外,這不是一個關於使用的問題;我想我會得到這些功能的原因。 – orome 2014-10-02 16:46:28

回答

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可能爲零,但是你想強制該值無論如何(或崩潰,如果它不存在)。然而,有沒有的機會是零,所以你不能有一個?或!!

test.two    // nil 

test.twoString?,其可以爲零。因爲它是可選的,你可以像你在代碼中一樣返回零。這真正的價值是.None,所以你看到的價值實際上是一個字符串?不是一個字符串。

test.two?    // nil 

這基本上和上面的一樣,只是你明確地說這個值可能是零。

//test.two!    // ERROR: EXEC_BAD_INSTRUCTION 

你永遠不可能用一個nil!不期待它崩潰。當你使用這個運算符時,它會強制一個值(所以你會有一個String,而不是String?)。但是,如果值爲零,有沒有的值強制出來,所以你最終崩潰的程序。

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) 

強制展開零值會使程序每次都崩潰。它也沒有意義,因爲解壓將返回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被隱式解開,所以?具有「重新包裝」它的效果:結果的類型現在是String?。這在這裏沒有什麼區別,但看看它在test.three已經指定String值之後的含義。

//test.three!   // ERROR: EXEC_BAD_INSTRUCTION 

以上是不可能解開nil。這似乎令人困惑,因爲聲明通常被描述爲產生一個「隱含解包」的變量;但如果它不是nil「應該被解讀爲」隱式地解開「。

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

與上述2相同。如果你有一個force-unwrapped變量,似乎是強行解開它,這是我不會建議的行爲。嘗試不經常使用強制展開的選項,如果您真的需要,大部分都需要處理部分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("!!!")你看到的只是輸出顯示在類中持有的所有變量,以及它們如何改變。

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

test.two現在是.Some("???"),所以當你調用它,也就是返回什麼:一個字符串?具有價值。當您強制解開它時,它現在返回.Some中保存的值而不會崩潰,因爲確實存在String。

test.two == nil   // false 
test.two? == nil  // false 

test.two仍是一個可選的,所以前兩個,當他們比較爲零,實現了「嘿,有。有的價值,所以它是不」。

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

強制展開值會將值從一個字符串變成test.two?到一個字符串。字符串從來沒有零,因爲如果他們是,他們將需要是可選的。將絕對爲String的值比較爲零將毫無意義,因爲知道它不是零;否則,程序會崩潰!

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

test.two是一個String ?,而不是一個String。爲了訪問字符串本身,你需要確保它在那裏訪問,使用?或者!

test.two?.isEmpty  // {Some false} 

這上面說, 「如果test.two包含一個String(不爲零),然後找到它是否是空的。」它說{Some false},因爲你正在訪問一個可選的成員,而不是一個直接的字符串。

test.two!.isEmpty  // false 

!,而另一方面,確實返回一個字符串。在字符串上調用.isEmpty要麼是true要麼是false,在這種情況下是false,因爲您將其設置爲非空字符串。

test.three    // "!!!" 

test.three力解開從它的字符串,在這種情況下工作,因爲它有一個值。

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

你把這個作爲一個正常的可選(非強制解開),所以你得到一些(字符串),而不是隻是一個字符串。

test.three!    // "!!!" 

既然你在它的聲明中強制解開它,它在這裏是強制解開的。

test.three == nil  // false 

這是另一個奇怪的行爲,因爲它可能應該是一個錯誤。它應該是一個字符串,不能與零比較,但在這裏發生了一些古怪的事情。當我發現這件事時,我會回覆你。

test.three? == nil  // false 

黃柏test.three作爲一個正常的可選的,並檢查是否它的狀態是.None,或爲零。

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

什麼一二上述應該像。無法將字符串與nil進行比較,因此會引發錯誤。

test.three.isEmpty  // false 

查看被強制出來的字符串值(它存在;否則,它會崩潰)。該字符串不是空的,所以它是錯誤的。

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

將它視爲字符串?如果test.three不爲零,則它從.Some(一個字符串)中取值,並評估它是否爲空,而不是。

test.three!.isEmpty  // false 

String被強制排除在可選項之外,並且直接調用isEmpty。它不是空的,所以它返回false。

我希望有助於澄清事情,我會讓你知道這是爲什麼一個案例是事情是這樣的,當我發現我自己:]

+0

說「anOptional?」是否是無操作是否正確?也就是說,'anOptional?'與'anOptional'完全相同,只有當後面的'.'或'[...]'有效時? – orome 2014-10-04 16:35:59

+0

@raxacoricofallapatorius你能指出你正在談論的例子嗎?我不太明白你在說什麼 – erdekhayser 2014-10-04 16:36:59

+0

例如'test.three?'在它自己的。這絕不會產生與'test.three'不同的任何東西。 – orome 2014-10-04 16:40:08

相關問題