2016-03-15 67 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),因为您无法定义类似“扩展字典”的值:可选'。 –