如何使用泛型函数拆解 swift 的可选末日金字塔



我们可以定义一个函数来拆除可选的末日金字塔,而不是使用多个可选绑定。

func if_let<T, U, V> (a: T?, _ b: U?, _ c: V?, fn:(T, U, V) -> () ){
    if let a = a {
        if let b = b {
            if let c = c {
                fn(a, b, c)
            }
        }
    }
}

然后我可以这样写:

var s1: String? = "s11"
var s2: String? = "s22"
var s3: String? = "s33"
if_let(s1, s2, s3) { s1, s2, s3 in
    print(("(s1) - (s2) - (s3)"))
}

然而,问题是如何使这个if_let函数更通用,以便它可以接受任意数量的参数。我的实现是这样的:

func if_let<T> (values: T?..., fn:(params: [T]) -> ()) {
    for value in values {
        guard value != nil else { return }
    }
    let unwrappedArray = values.map{ $0! }
    fn(params: unwrappedArray)
}

我试着映射数组,得到一个所有元素都展开的新数组,然后调用fn。但当我再次运行测试时,我得到了一个编译错误:

无法将类型为String?的值转换为所需的参数类型"_?"

有人能解释并纠正这个错误吗?

问题是if_let的第二个实现不再将(T,U,V)->()类型的函数作为最终参数。它现在需要一个类型为([T])->()的函数。如果你用一个调用它,它会编译:

if_let(s1, s2, s3) { args in // or: (args: [String])->() in
    print("(args[0]) - (args[1]) - (args[2])")
}

一个相关的注释,而不是对特定问题的回答:有了Swift 2,你就不必再进入末日金字塔了

let a: String? = nil
let b: Int? = nil
let c: Double? = nil
// possible mutate...
if let a = a, b = b, c = c {
    // do something with shadow vars
}