2016-03-15 177 views
4

零值我有一個操場文件下面的代碼:檢查斯威夫特字典擴展

extension Dictionary { 

    func test() { 

     for key in self.keys { 
      self[key] 
     } 
    } 
} 

var dict: [String: AnyObject?] = [ 
    "test": nil 
] 

dict.test() 

我從此將參考線for-each循環中的輸出,因爲它是何等的重要。在這個特定的例子中,輸出是nil

當我改變for-each循環看起來像這樣:

for key in self.keys { 
    print(self[key]) 
} 

輸出爲"Optional(nil)\n"

我真正想要做的是檢查零值,但代碼:

for key in self.keys { 
    self[key] == nil 
} 

輸出false。我試圖

的另一件事是以下幾點:

for key in self.keys { 
    self[key] as! AnyObject? == nil 
} 

產生錯誤:

Could not cast value of type 'Swift.Optional<Swift.AnyObject>' to 'Swift.AnyObject' 

任何幫助,非常感謝!

+0

這是塑造了一個很好的問題,但你可以請你回去說(1)你在做什麼和(2)什麼是實際發生的事情? – matt

+1

下面是一個演示如何檢查字典中的「雙選項」的示例:http://stackoverflow.com/questions/27225232/two-or-more-optionals-in-swift,以及如何區分「值密鑰不存在「和」密鑰存在且爲零「。 –

回答

6

您看到了成那種亂七八糟的,因爲一本字典,其值可以nil您呈現的前景,一個雙層包裝可選,因此2種nil。有nil,你會得到如果密鑰丟失,然後nil,你會得到如果密鑰是不是丟失,你解開提取的結果。不幸的是,你正在一個操場上進行測試,這是一個探索這個區別的不好的場所。

要明白我的意思,只考慮以下幾點:

var d : [String:Int?] = ["Matt":1] 
let val = d["Matt"] 

什麼是val類型?它是Int?? - 一個Int包裹在一個可選的包裹在另一個可選。這是因爲裏面的值根據定義,字典被定義爲一個Int包裝在一個Optional中,然後通過其另一個中的鍵值獲取值可選。

所以,現在讓我們去一個遠一點,做這樣說:

var d : [String:Int?] = ["Matt":nil] 
let val = d["Matt"] 

什麼是val?那麼,操場可能它是nil,但事實更加複雜;它的nil包裹在另一個可選。這是最容易看到,如果你打印val,在這種情況下,你會得到,而不是nil,但"Optional(nil)"

但是,如果我們嘗試的東西在那裏,關鍵是根本不存在,我們得到了一個不同的答案

let val2 = d["Alex"] 

這確實nil,表示密鑰丟失。如果我們打印val2,我們得到"nil"。操場上沒有作出區分(它說nil兩個valval2),但轉換爲字符串(這是什麼print一樣)顯示的差異。

所以,問題的一部分,是這整個雙層包裝可選的東西,而另一部分是,遊樂場代表雙層包裝可選在一個非常誤導的方式。

MORAL 1:其值類型爲Optional的字典可能非常棘手。

道德2:遊樂場是魔鬼的工作。避免它們。使用一個真正的應用程序,並使用記錄到控制檯或調試器的變量窗格中,看看究竟發生了什麼事情。

+0

關於此事的非常好的文章,以及關於它的建議,請訪問Apple網站:https://developer.apple.com/swift/blog/?id=12 – matt

2

察看字典值nil纔有意義,如果 字典中的值是一個Optional型,這意味着你必須 限制您的擴展方法的話。

這是可能通過定義所有可選類型符合 的協議(比較How can I write a function that will unwrap a generic property in swift assuming it is an optional type?,這是Creating an extension to filter nils from an Array in Swift只是輕微的修改):

protocol OptionalType { 
    typealias Wrapped 
    var asOptional : Wrapped? { get } 
} 

extension Optional : OptionalType { 
    var asOptional : Wrapped? { 
     return self 
    } 
} 

現在可以限定與被限制爲一個擴展方法可選值類型的 字典:

extension Dictionary where Value : OptionalType { 

    func test() { 
     for key in self.keys { ... } 
    } 
} 

馬特已經解釋過,self[key]只能是nil如果該鍵 缺少字典中,並不能在這裏發生。所以你 可以隨時檢索該密鑰的值

  let value = self[key]! 

在該循環內。好,枚舉鍵和值:

 for (key, value) in self { ... } 

現在value是字典值(key),其類型 符合OptionalType。使用 你會得到一個可選的,可以對無測試的asOptional協議屬性:

   if value.asOptional == nil { ... } 

或可選的結合使用。

把所有一起:

extension Dictionary where Value : OptionalType { 

    func test() { 
     for (key, value) in self { 
      if let unwrappedValue = value.asOptional { 
       print("Unwrapped value for '\(key)' is '\(unwrappedValue)'") 
      } else { 
       print("Value for '\(key)' is nil") 
      } 
     } 
    } 
} 

例子:

var dict: [String: AnyObject?] = [ 
    "foo" : "bar", 
    "test": nil 
] 

dict.test() 

輸出:

 
Value for 'test' is nil 
Unwrapped value for 'foo' is 'bar' 
+0

您能解釋'asOptional'屬性在做什麼嗎? ?它是否簡單地將'self'作爲可選項再次包裝?我通過創建一個新的變量爲'AnyObject?'進行測試,併爲其分配'「a」。我將變量原樣打印出來並使用'asOptional',並得到了相同的結果。 – Alex311

+0

@ Alex311:是的,它返回值本身,但是作爲'Wrapped?',以便編譯器可以將它視爲可選項。這是一個「技巧」或「解決方法」(返回到https://forums.developer.apple.com/message/12078),因爲您無法定義類似「擴展字典」的值:可選'。 –