Swift:"Where" 对比 "If"
Swift: "Where" vs "If"
这两种语法有区别吗?如果没有,有什么好处吗?
if let userName = userNameTextField.text where userName.characters.count > 0,
let password = passwordTextField.text where password.characters.count > 0,
let confirmation = confirmationTextField.text where confirmation == password
else {
return false
}
和:
if userNameTextField.text?.characters.count > 0 &&
passwordTextField.text?.characters.count > 0 &&
confirmationTextField.text == passwordTextField.text
{
return false
}
首先请注意,可选绑定条件中的 where
子句在 Swift 3.0 中已弃用,取而代之的是 ,
.
即
let opt: Int?
/* Swift < 3 */
if let opt = opt where opt == 42 { /* ... */ }
/* Swift >= 3 */
if let opt = opt, opt == 42 { /* ... */ }
其次,您的第二个示例块不会在 Swift >= 3.0 中编译,因为可选链接的 optional 结果未展开; Swift 3.0(感谢@MartinR)中删除了将可选值与文字进行比较,根据以下已实施的建议:
- Evolution proposal SE-0121: Remove Optional Comparison Operators
- Evolution proposal SE-0123: Disallow coercion to optionals in operator arguments
userNameTextField.text?.characters.count > 0 &&
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
this is an optional that, for Swift >= 3.0, needs to be unwrapped
prior to comparing it to the integer literal */
现在,继续回答您的 "is there any difference ..." 问题,假设我们查看您为 Swift 3 确定的两个选项。
- 您可以选择绑定
String
属性 text
of userNameTextField
的可选值,如果您想在 或 之后的 if 块
- 如果您只想确定
text
属性 不是 nil
或空的 (""
),您可以省略绑定以支持或简单地检查它的character.count
例如:
struct Foo {
var bar: String?
}
var foo = Foo()
/* if you want to use foo.bar within the if block */
if let str = foo.bar, str.characters.count > 0 {
// do something with str ...
print(str)
}
/* if you only need to ascertain foo.bar is not nil
and not empty */
if (foo.bar?.characters.count ?? 0) > 0 {
// do something with str ...
print("not empty")
}
// alternatively ... (not nil or empty)
if !(foo.bar?.isEmpty ?? true) {
// do something with str ...
print("not empty")
}
如果你只是想确定后者和 return false
以防断言失败,你可能更喜欢使用 guard
语句而不是 if
:
guard (foo.bar?.characters.count ?? 0) > 0 else { return false }
// ... if no false return, proceed with app flow here ...
// alternatively ...
guard !(foo.bar?.isEmpty ?? true) else { return false }
这两个版本都无法在 Swift 3 中使用。我认为在第一个版本中,您打算使用 guard
而不是 let
。
对于 Swift 3,您想执行以下操作:
guard
let userName = userNameTextField.text,
let password = passwordTextField.text,
let confirmation = confirmationTextField.text,
userName.characters.count > 0,
password.characters.count > 0,
confirmation == password
else {
return false
}
如其他一些答案所述,在 Swift 3 中使用您的方法存在问题。但是如果你用的是Swift2,下面是我对你问题的回答。
两者完全一样,只有一处不同。这两种方法都是测试 nil 值,然后在该值不为 nil 时引入布尔测试。例如在你的行中,
if let userName = userNameTextField.text where userName.characters.count > 0
您正在测试 userNameTextField 是否不为 nil,然后您正在测试其计数是否大于零。同样的事情适用于这一行,
if userNameTextField.text?.characters.count > 0
除了它更短更易读。
因为这两种方法都在 'if' 语句中,所以它们都评估为 true 或 false 并实现相同的目的。
然而,它们的区别在于使用 'where' 子句,您可以在绑定或模式之后引入布尔测试,而不管两者之间是否存在潜在语义 link .所以我基本上可以用 'where' 子句来做到这一点,
if let userName = userNameTextField.text where age > 0
userNameTextField 和 age 之间没有语义 link。正如您所想象的,这可能不是您想要的,这可能会很快导致错误。
这两种语法有区别吗?如果没有,有什么好处吗?
if let userName = userNameTextField.text where userName.characters.count > 0,
let password = passwordTextField.text where password.characters.count > 0,
let confirmation = confirmationTextField.text where confirmation == password
else {
return false
}
和:
if userNameTextField.text?.characters.count > 0 &&
passwordTextField.text?.characters.count > 0 &&
confirmationTextField.text == passwordTextField.text
{
return false
}
首先请注意,可选绑定条件中的 where
子句在 Swift 3.0 中已弃用,取而代之的是 ,
.
即
let opt: Int?
/* Swift < 3 */
if let opt = opt where opt == 42 { /* ... */ }
/* Swift >= 3 */
if let opt = opt, opt == 42 { /* ... */ }
其次,您的第二个示例块不会在 Swift >= 3.0 中编译,因为可选链接的 optional 结果未展开; Swift 3.0(感谢@MartinR)中删除了将可选值与文字进行比较,根据以下已实施的建议:
- Evolution proposal SE-0121: Remove Optional Comparison Operators
- Evolution proposal SE-0123: Disallow coercion to optionals in operator arguments
userNameTextField.text?.characters.count > 0 && /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is an optional that, for Swift >= 3.0, needs to be unwrapped prior to comparing it to the integer literal */
现在,继续回答您的 "is there any difference ..." 问题,假设我们查看您为 Swift 3 确定的两个选项。
- 您可以选择绑定
String
属性text
ofuserNameTextField
的可选值,如果您想在 或 之后的 if 块
- 如果您只想确定
text
属性 不是nil
或空的 (""
),您可以省略绑定以支持或简单地检查它的character.count
例如:
struct Foo {
var bar: String?
}
var foo = Foo()
/* if you want to use foo.bar within the if block */
if let str = foo.bar, str.characters.count > 0 {
// do something with str ...
print(str)
}
/* if you only need to ascertain foo.bar is not nil
and not empty */
if (foo.bar?.characters.count ?? 0) > 0 {
// do something with str ...
print("not empty")
}
// alternatively ... (not nil or empty)
if !(foo.bar?.isEmpty ?? true) {
// do something with str ...
print("not empty")
}
如果你只是想确定后者和 return false
以防断言失败,你可能更喜欢使用 guard
语句而不是 if
:
guard (foo.bar?.characters.count ?? 0) > 0 else { return false }
// ... if no false return, proceed with app flow here ...
// alternatively ...
guard !(foo.bar?.isEmpty ?? true) else { return false }
这两个版本都无法在 Swift 3 中使用。我认为在第一个版本中,您打算使用 guard
而不是 let
。
对于 Swift 3,您想执行以下操作:
guard
let userName = userNameTextField.text,
let password = passwordTextField.text,
let confirmation = confirmationTextField.text,
userName.characters.count > 0,
password.characters.count > 0,
confirmation == password
else {
return false
}
如其他一些答案所述,在 Swift 3 中使用您的方法存在问题。但是如果你用的是Swift2,下面是我对你问题的回答。
两者完全一样,只有一处不同。这两种方法都是测试 nil 值,然后在该值不为 nil 时引入布尔测试。例如在你的行中,
if let userName = userNameTextField.text where userName.characters.count > 0
您正在测试 userNameTextField 是否不为 nil,然后您正在测试其计数是否大于零。同样的事情适用于这一行,
if userNameTextField.text?.characters.count > 0
除了它更短更易读。
因为这两种方法都在 'if' 语句中,所以它们都评估为 true 或 false 并实现相同的目的。
然而,它们的区别在于使用 'where' 子句,您可以在绑定或模式之后引入布尔测试,而不管两者之间是否存在潜在语义 link .所以我基本上可以用 'where' 子句来做到这一点,
if let userName = userNameTextField.text where age > 0
userNameTextField 和 age 之间没有语义 link。正如您所想象的,这可能不是您想要的,这可能会很快导致错误。