我有两种不同的场景,我需要测试"选项"可选类型。如果变量是.None
或.Some
而不是使用笨重的switch语句,我无法计算如何显式测试。如何使用Someness
语句测试if
?
我正在写一个地址格式化程序,我的输入是一些字符串?类型。在此示例中,(str != nil)
的简单测试将起作用。但是,由于我的另一个需要是处理双重可选'并且零测试无法区分.Some(.None)
和.None
此问题的解决方案也将解决该问题。
这是一个使用switch
let address1:String? = "123 Main St"
let address2:String? = nil
let apt:String? = "101"
let components = [address1, address2, apt].filter( { (c) -> Bool in
switch c {
case .Some: return true
case .None: return false
}
}).map { return $0! } //Had to map because casting directly to [String] crashes
print(", ".join(components)) //"123 Main St, 101"
我希望看到的内容与if
类似:
let nice = ["123 Main St", nil, "303"].filter { (c) -> Bool in
return (c == .Some)
}
print(", ".join(nice))
这是零测试无法运行的地方。如果有什么东西是String?它可以是.None
,.Some(.None)
或.Some(.Some(String))
中的任何一个。在我的例子中,变量携带来自api调用的recordID,该调用可能完全缺失(.None
),值(.Some(.Some("ABDEFG")
)或显式NULL
({{1} })。
.Some(.None)
通过另一篇SO帖子,我发现了一个像这样的解决方法,但是对于一个随意的读者发生了什么并不是很清楚:
let teamNoneNone: String?? = .None
let teamSomeNone: String?? = .Some(.None)
let teamSomeSome: String?? = "My favorite local sportsball team"
if teamNoneNone == nil {
print("teamNoneNone is nil but is it .None? We don't know!") //prints
} else {
print("teamNoneNone is not nil")
}
if teamSomeNone == nil {
print("teamSomeNone is nil")
} else {
print("teamSomeNone is not nil but is it .Some(.None)? We don't know!") //prints
}
if teamSomeSome == nil {
print("teamSomeSome is nil but is it .None? We don't know!")
} else {
print("teamSomeSome is not nil but is it .Some(.None) or .Some(.Some())? We don't know!") //prints
}
答案 0 :(得分:3)
if let
测试值是否为.None
,如果不是,则将其解包并将其绑定到if语句中的局部变量。
如果.Some
没有删除,那么使用.None
和if let
开关实际上是处理选项的第二种方法。但它几乎总是这样,特别是现在你可以在一个语句中执行多个if let
,跟随最新版本的Swift 1.2进行生产。
想要过滤掉集合中的nils是一项常见的任务,Haskell有一个标准函数,称为catMaybe
。这是一个版本,我称之为catSome
,它可以在Swift中实现这个技巧:
func catSome<T>(source: [T?]) -> [T] {
var result: [T] = []
// iterate over the values
for maybe in source {
// if this value isn’t nil, unwrap it
if let value = maybe {
// and append it to the array
result.append(value)
}
}
return result
}
let someStrings: [String?] = ["123 Main St", nil, "101"]
catSome(someStrings) // returns ["123 Main St", "101"]
双重包装的选项有点痛苦,所以最好的解决方案是首先避免它们 - 通常是通过使用可选链接或flatMap
。
但如果你确实发现自己有一些,并且你关心的只是内在价值,你可以用双if let
打开它们:
// later parts of the let can rely on the earlier
if let outer = teamSomeSome, teamName = outer {
println("Fully unwrapped team is \(teamName)")
}
如果您想明确知道双重可选项在外部值中是否包含内部nil
,但本身不是nil
,则可以将if let
与{{where
一起使用1}}子句:
if let teamSomeMaybe = teamSomeNone where teamSomeMaybe == nil {
// this will be executed only if it was .Some(.None)
println("SomeNone")
}
where
子句是一个额外的条件,可以应用于展开的值。