我们说我有返回可选的功能。如果成功则错误和价值为零:
func foo() -> Bar? { ... }
我可以使用以下代码来使用此功能:
let fooResultOpt = foo()
if let fooResult = fooResultOpt {
// continue correct operations here
} else {
// handle error
}
然而,对于任何非平凡的代码,这种方法几乎没有问题:
最终执行的错误处理很容易错过。当错误处理代码跟随函数调用时,它会好得多。
正确的操作代码缩进一级。如果我们有另一个函数要调用,我们必须再缩进一次。
使用C,通常可以写出这样的内容:
Bar *fooResult = foo();
if (fooResult == null) {
// handle error and return
}
// continue correct operations here
我找到了两种使用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
我是否错过了规范中的某些内容,或者是否有其他方法可以编写好看的Swift代码?
答案 0 :(得分:2)
你的假设是正确的 - 没有"否定if-let" Swift中的语法。
我怀疑其中一个原因可能是语法完整性。在整个Swift(通常在其他C语言中),如果你有一个可以绑定局部符号的语句(即命名新变量并赋予它们值)并且可以有一个块体(例如if,while,for),那些绑定范围限定为所述块。让一个块语句将符号绑定到其封闭的范围将是不一致的。
但是,考虑一下这仍然是一个合理的事情 - 我建议filing a bug并看看Apple对此有何看法。答案 1 :(得分:2)
这就是模式匹配的全部内容,也是这项工作的工具:
let x: String? = "Yes"
switch x {
case .Some(let value):
println("I have a value: \(value)")
case .None:
println("I'm empty")
}
当你不需要双腿时,if-let
形式只是一种便利。
答案 2 :(得分:1)
如果您正在编写的是一组执行相同转换序列的函数,例如处理REST调用返回的结果时(检查响应不是nil,检查状态,检查app / server错误,解析响应)等等),我要做的是创建一个管道,在每个步骤转换输入数据,最后返回nil
或某种类型的转换结果。
我选择了>>>
自定义运算符,它可以直观地显示数据流,但当然可以自由选择:
infix operator >>> { associativity left }
func >>> <T, V> (params: T?, next: T -> V?) -> V? {
if let params = params {
return next(params)
}
return nil
}
运算符是一个函数,它接收某种类型的值作为输入,以及一个将值转换为另一种类型值的闭包。如果值不是nil,则函数调用闭包,传递值,并返回其返回值。如果值为nil
,则运算符返回nil
。
可能需要一个例子,所以让我假设我有一个整数数组,我想按顺序执行以下操作:
这些是4个功能:
func sumArray(array: [Int]?) -> Int? {
if let array = array {
return array.reduce(0, combine: +)
}
return nil
}
func powerOf2(num: Int?) -> Int? {
if let num = num {
return num * num
}
return nil
}
func module5(num: Int?) -> (Int, Int)? {
if let num = num {
return (num / 5, num % 5)
}
return nil
}
func sum(params: (num1: Int, num2: Int)?) -> Int? {
if let params = params {
return params.num1 + params.num2
}
return nil
}
这就是我的用法:
let res: Int? = [1, 2, 3] >>> sumArray >>> powerOf2 >>> module5 >>> sum
此表达式的结果是nil或管道的最后一个函数中定义的类型的值,在上面的示例中为Int
。
如果您需要做更好的错误处理,可以定义这样的枚举:
enum Result<T> {
case Value(T)
case Error(MyErrorType)
}
并使用Result<T>
替换上述函数中的所有可选项,并返回Result.Error()
而不是nil
。
答案 3 :(得分:1)
我发现了一种看起来比替代方案更好的方法,但它以未经推荐的方式使用语言功能。
使用问题代码的示例:
let fooResult: Bar! = foo();
if fooResult == nil {
// handle error and return
}
// continue correct operations here
fooResult可以用作普通变量,不需要使用“?”要么 ”!”后缀。
Apple文档说:
如果在首次定义可选项后立即确认可选项的值存在,并且可以假定在此后的每个点都存在,则隐式解包的选项会很有用。 Swift中隐式解包选项的主要用途是在类初始化期间,如Unowned References和Implicitly Unwrapped Optional Properties中所述。
答案 4 :(得分:0)
以下内容如何:
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