我仍然围绕在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循环?还是有另一种我忽视的首选方法?
答案 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>>
)不是。
正如你所说,有两种主要方法可以解决这个问题。
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)")
}
}
这是两个选项中更极端的,因为如果foo
是nil
,它会强制你打破范围(当前函数),这很可能不是你想做的事情,看作nil
是默认值,可能是完全(逻辑上)可行的价值。
if let
func printNamesAndValues(of foo: [String: String]? = nil) -> Void {
if let foo = foo else {
for (name, value) in foo {
print("\(name) is \(value)")
}
}
}
如果foo
为nil
,此方法将跳过循环,但方法的其余部分将继续。
答案 2 :(得分:1)
当您需要使用需要非Opional值的Optionals时,有以下几种方法:
使用强制展开(!
)
仅当您100%确定Optional不能为零时才执行此操作。你的情况当然不符合。
使用可选链接(?.
)
仅在您想要使用某些方法时有效。在许多情况下,您需要结合其他解决方案。 Eendje的回答就是一个很好的例子。
使用可选绑定(if-let
或guard-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"