循环遍历可选字典的名称/值对

时间:2016-12-15 16:20:46

标签: swift

我仍然围绕在Swift中使用选项来包装我的大脑,并且很好奇如何最好地处理可选字典参数的名称/值对的循环。考虑:

func printNamesAndValues(of foo: [String: String]?=nil) -> Void {
    for (name, value) in foo {
        print("\(name) is \(value)")
    }
}

printNamesAndValues()
printNamesAndValues(of: nil)
printNamesAndValues(of: ["a": "b"])

for循环行上的Swift 3编译器错误,报告:

  

可选类型的值[String:String]?"没有打开;你的意思是使用'!'或者'?'?

在这种情况下,似乎强制解包是错误的方法,因为foo可以通过默认参数或调用者传递nil为零。那么,我应该在guard循环之前使用for吗?或者使用if foo != nil { ... }包装for循环?还是有另一种我忽视的首选方法?

5 个答案:

答案 0 :(得分:1)

完全取决于你。有几种方法可以做到这一点

guard let dict = foo else { return }
// use dict

if let dict = foo {
    // use dict
}

if foo != nil {
    // use foo! - not recommended actually
}

如果执行此方法需要字典,我更喜欢guard(但这可以通过使foo参数不可选来避免)。

如果使用这种方法,我宁愿将声明修改为

func printNamesAndValues(of foo: [String: String] = [:]) -> Void {}

答案 1 :(得分:1)

正确的方法因您的意图而异。编译器抱怨选项的原因是因为没有最好的方法来处理它们,所以由你作为程序员来决定做什么。这就是编译器不能单独处理它们的原因。

在您的情况下,您必须先将foo打开,然后才能在for循环的右侧使用它。请注意,[String: String](a.k.a。Dictionary<String, String)是一个序列,但[String: String]?(a.k.a。Optional<Dictionary<String, String>>)不是。

正如你所说,有两种主要方法可以解决这个问题。

  1. 使用guard let

     func printNamesAndValues(of foo: [String: String]? = nil) -> Void {
        guard let foo = foo else { return }
        for (name, value) in foo {
            print("\(name) is \(value)")
        }
    }
    

    这是两个选项中更极端的,因为如果foonil,它会强制你打破范围(当前函数),这很可能不是你想做的事情,看作nil是默认值,可能是完全(逻辑上)可行的价值。

  2. 使用if let

    func printNamesAndValues(of foo: [String: String]? = nil) -> Void {
        if let foo = foo else {
            for (name, value) in foo {
                print("\(name) is \(value)")
            }
        }
    }
    

    如果foonil,此方法将跳过循环,但方法的其余部分将继续。

答案 2 :(得分:1)

当您需要使用需要非Opional值的Optionals时,有以下几种方法:

  • 使用强制展开(!

    仅当您100%确定Optional不能为零时才执行此操作。你的情况当然不符合。

  • 使用可选链接(?.

    仅在您想要使用某些方法时有效。在许多情况下,您需要结合其他解决方案。 Eendje的回答就是一个很好的例子。

  • 使用可选绑定(if-letguard-let

    您已经有几个答案描述了这一点。

  • 使用nil-coalescing运算符(??

    提供默认值

    你可以这样写:

    func printNamesAndValues(of foo: [String: String]?=nil) -> Void {
        for (name, value) in foo ?? [:] {
            print("\(name) is \(value)")
        }
    }
    

    [:]是一个空字典,当??的左侧(在上面的代码中,foo)为零时,右侧([:] )被评估并成为操作的结果。对于空字典,for-in不执行循环体。

似乎第三个和第四个都适合你的情况。请试试。

答案 3 :(得分:0)

将整个事物包裹在if let中,以便在循环之前确定它是否为零。

func printNamesAndValues(of foo: [String: String]?=nil) -> Void {
    if let f = foo {
       for (name, value) in f {
           print("\(name) is \(value)")
       }
    }
}

printNamesAndValues()
printNamesAndValues(of: nil)
printNamesAndValues(of: ["a": "b"])

答案 4 :(得分:0)

在您的情况下,只需使用可选链接就足够了。

func printNamesAndValues(of foo: [String: String]? = nil) -> Void {
    foo?.forEach { print("\($0.0) is \($0.1)") }
}

printNamesAndValues()                 // nothing happens
printNamesAndValues(of: nil)          // nothing happens
printNamesAndValues(of: ["a": "b"])   // prints: "a is b"