Swift 快速,可选展开,在条件允许时反转
假设我有一个返回可选值的函数。错误时为零,成功时为值:Swift 快速,可选展开,在条件允许时反转,swift,error-handling,optional,Swift,Error Handling,Optional,假设我有一个返回可选值的函数。错误时为零,成功时为值: func foo() -> Bar? { ... } 我可以使用以下代码来使用此函数: let fooResultOpt = foo() if let fooResult = fooResultOpt { // continue correct operations here } else { // handle error } 但是,对于任何非平凡的代码,这种方法几乎没有问题: 最后执行了错误处理,很容易遗漏某些
func foo() -> Bar? { ... }
我可以使用以下代码来使用此函数:
let fooResultOpt = foo()
if let fooResult = fooResultOpt {
// continue correct operations here
} else {
// handle error
}
但是,对于任何非平凡的代码,这种方法几乎没有问题:
Bar *fooResult = foo();
if (fooResult == null) {
// handle error and return
}
// continue correct operations here
enum Result<T> {
case Value(T)
case Error(MyErrorType)
}
我发现有两种方法可以使用Swift实现类似的代码风格,但我不喜欢这两种方法
let fooResultOpt = foo()
if fooResult == nil {
// handle error and return
}
// use fooResultOpt! from here
let fooResult = fooResultOpt! // or define another variable
如果我到处都写“!”的话,那对我的品味就不好了。我可以引入另一个变量,但看起来也不太好。理想情况下,我希望看到以下内容:
if !let fooResult = foo() {
// handle error and return
}
// fooResult has Bar type and can be used in the top level
func foo(i:Int) ->Int? {
switch i {
case 0: return 0
case 1: return 1
default: return nil
}
}
var error:Int {
println("Error")
return 99
}
for i in 0...2 {
var bob:Int = foo(i) ?? error
println("\(i) produces \(bob)")
}
我是否遗漏了规范中的某些内容,或者是否有其他方法来编写美观的Swift代码?您的假设是正确的,Swift中没有“如果让则否定”语法 我怀疑其中一个原因可能是语法的完整性。在整个Swift(通常在其他C语言中)中,如果您有一条语句可以绑定本地符号(即命名新变量并给它们赋值),并且可以有一个块体(例如if、while、for),那么这些绑定的作用域就是所述块。相反,让block语句将符号绑定到其封闭范围是不一致的
尽管如此,这仍然是一件值得考虑的事情——我会推荐并看看苹果对此做了些什么 这就是模式匹配的全部内容,也是用于此项工作的工具:
let x: String? = "Yes"
switch x {
case .Some(let value):
println("I have a value: \(value)")
case .None:
println("I'm empty")
}
if-let
表单只是在您不需要两条腿时的一种方便。如果您编写的是一组执行相同转换序列的函数,例如在处理REST调用返回的结果时(检查响应是否为零、检查状态、检查应用程序/服务器错误、解析响应等),我要做的是创建一个管道,在每个步骤转换输入数据,最后返回nil
或某一类型的转换结果
我选择了>>
自定义运算符,它直观地指示数据流,但当然可以自由选择自己的运算符:
infix operator >>> { associativity left }
func >>> <T, V> (params: T?, next: T -> V?) -> V? {
if let params = params {
return next(params)
}
return nil
}
我会这样使用:
let res: Int? = [1, 2, 3] >>> sumArray >>> powerOf2 >>> module5 >>> sum
此表达式的结果为nil或管道的最后一个函数中定义的类型的值,在上面的示例中为Int
如果需要更好地处理错误,可以定义如下枚举:
Bar *fooResult = foo();
if (fooResult == null) {
// handle error and return
}
// continue correct operations here
enum Result<T> {
case Value(T)
case Error(MyErrorType)
}
枚举结果{
案例值(T)
案例错误(MyErrorType)
}
并将上述函数中的所有选项替换为
Result
,返回Result.Error()
,而不是nil
,我找到了一种比其他方法看起来更好的方法,但它以不推荐的方式使用了语言功能
使用问题代码的示例:
let fooResult: Bar! = foo();
if fooResult == nil {
// handle error and return
}
// continue correct operations here
fooResult可以用作普通变量,不需要使用“?”或“!”后缀
苹果的文档说:
当一个可选项的值在第一次定义该可选项之后立即被确认存在时,隐式展开的可选项是有用的,并且可以肯定地假设该可选项在此后的每一点上都存在。Swift中隐式展开选项的主要用途是在类初始化期间,如无主引用和隐式展开可选属性中所述
那么以下内容如何:
if !let fooResult = foo() {
// handle error and return
}
// fooResult has Bar type and can be used in the top level
func foo(i:Int) ->Int? {
switch i {
case 0: return 0
case 1: return 1
default: return nil
}
}
var error:Int {
println("Error")
return 99
}
for i in 0...2 {
var bob:Int = foo(i) ?? error
println("\(i) produces \(bob)")
}
结果如下:
0 produces 0
1 produces 1
Error
2 produces 99
谢谢,但是您的解决方案与语法if(let value=x){…}else{…}没有什么不同,并且具有我在问题中提到的所有缺点。谢谢您的回答,这是一个很好的方法,但在一般情况下,它似乎非常非强制性,很难扩展和修改。它可能非常适合某些情况,在这些情况下,数据流是自然的。是的,它不是一种通用的方式,它来自函数式编程。也许这不是解决您具体问题的正确方法,但我希望您将来会发现它很有用;-)