如何测试字符串的可选性?
How to test the Optionality of a String?
我有两种不同的场景需要测试可选类型的 "optionality"。除了使用笨拙的 switch 语句之外,我无法弄清楚如何 显式 测试变量是 .None
还是 .Some
。如何使用 if
语句测试 Someness
?
场景 1
我正在写一个地址格式化程序,我的输入是一些字符串?类型。在此示例中,(str != nil)
的简单测试将起作用。但是,由于我的另一个需要是在处理 'double optional' 和 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 [=10=]! } //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))
场景 2
这是 nil 测试不起作用的地方。如果某物是字符串??它可以是 .None
、.Some(.None)
或 .Some(.Some(String))
中的任何一个。在我的例子中,该变量携带来自 api 调用的 recordID,该调用可能完全缺失 (.None
)、一个值 (.Some(.Some("ABDEFG")
),或显式 NULL
( .Some(.None)
)。
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
}
通过另一个 SO post 我找到了这样的解决方法,但不太清楚临时 reader:
发生了什么
if let team: String? = teamSomeNone {
print("teamSomeNone is Some(.None)") //prints
} else {
print("teamSomeNone is .Some(.Some())")
}
if let
测试一个值是否为 .None
,如果不是,则解包并将其绑定到 if 语句中的局部变量。
将 switch 与 .Some
和 .None
一起使用实际上是处理可选值的次要方法,如果 if let
没有削减它的话。但它几乎总是如此,尤其是现在您可以在一条语句中执行多个 if let
s,在最新发布的 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
子句:
if let teamSomeMaybe = teamSomeNone where teamSomeMaybe == nil {
// this will be executed only if it was .Some(.None)
println("SomeNone")
}
where
子句是一个额外的条件,可以应用于展开的值。
我有两种不同的场景需要测试可选类型的 "optionality"。除了使用笨拙的 switch 语句之外,我无法弄清楚如何 显式 测试变量是 .None
还是 .Some
。如何使用 if
语句测试 Someness
?
场景 1
我正在写一个地址格式化程序,我的输入是一些字符串?类型。在此示例中,(str != nil)
的简单测试将起作用。但是,由于我的另一个需要是在处理 'double optional' 和 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 [=10=]! } //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))
场景 2
这是 nil 测试不起作用的地方。如果某物是字符串??它可以是 .None
、.Some(.None)
或 .Some(.Some(String))
中的任何一个。在我的例子中,该变量携带来自 api 调用的 recordID,该调用可能完全缺失 (.None
)、一个值 (.Some(.Some("ABDEFG")
),或显式 NULL
( .Some(.None)
)。
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
}
通过另一个 SO post 我找到了这样的解决方法,但不太清楚临时 reader:
发生了什么if let team: String? = teamSomeNone {
print("teamSomeNone is Some(.None)") //prints
} else {
print("teamSomeNone is .Some(.Some())")
}
if let
测试一个值是否为 .None
,如果不是,则解包并将其绑定到 if 语句中的局部变量。
将 switch 与 .Some
和 .None
一起使用实际上是处理可选值的次要方法,如果 if let
没有削减它的话。但它几乎总是如此,尤其是现在您可以在一条语句中执行多个 if let
s,在最新发布的 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
子句:
if let teamSomeMaybe = teamSomeNone where teamSomeMaybe == nil {
// this will be executed only if it was .Some(.None)
println("SomeNone")
}
where
子句是一个额外的条件,可以应用于展开的值。