2 functional-programming swift swift2
在Swift 2中,即使函数中没有任何调用可以抛出,下面的函数也不会编译.
func function1<T, U>(f: Optional<T -> U>, x: Optional<T>) -> Optional<U> {
return f.flatMap(x.map) // Call can throw, but it is not marked with 'try' and the error is not handled
}
Run Code Online (Sandbox Code Playgroud)
此版本的函数与第一个版本相同(并且更详细),但它编译.
func function2<T, U>(f: Optional<T -> U>, x: Optional<T>) -> Optional<U> {
return f.flatMap { g in
x.map(g)
}
}
Run Code Online (Sandbox Code Playgroud)
这些版本不完全相同,我解释原因.
假设你有函数,rethrows因为它接受抛出函数作为参数:
func a(x: () throws -> ()) rethrows {
try x()
}
Run Code Online (Sandbox Code Playgroud)
所以a(x)只有投掷才会x()抛出.
如果你有b抛出的功能:
func b() throws {
}
Run Code Online (Sandbox Code Playgroud)
然后你必须a(b)用try 调用:
try a(b)
a(b) // gives "Call can throw but is not marked with 'try'"
Run Code Online (Sandbox Code Playgroud)
但如果你传递给a不投掷功能:
func c() {
}
Run Code Online (Sandbox Code Playgroud)
然后斯威夫特编译器足够聪明,以确定x()在a函数体实际上不扔,它允许简单地调用a(c):
a(c) // it's ok
Run Code Online (Sandbox Code Playgroud)
这是因为:
throws关键字是函数类型的一部分,nonthrowing函数是抛出函数的子类型.因此,您可以在与抛出函数相同的位置使用非抛出函数.
回到你的例子.
Optional.flatMap() 定义为:
public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?
Run Code Online (Sandbox Code Playgroud)
在你的例子中f.flatMap有类型((T -> U) throws -> U?) rethrows -> U?.
你看到它重新抛出,因为它接受抛出函数参数并且必须被调用,try除非f有类型Wrapped -> U?并且不抛出.
Optional.map 定义为:
public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
Run Code Online (Sandbox Code Playgroud)
所以x.map有型(T throws -> U) rethrows -> U?.
当你调用f.flatMap { g in x.map(g) }编译器看到它g有T -> U类型并且不抛出时x.map(g),{ g in x.map(g) }并且f.flatMap { g in x.map(g) }都是安全的并且不抛出.
但是,当你调用f.flatMap(x.map)所有编译器看到的那个x.map有 (T throws -> U) rethrows -> U?类型并且可以(重新)抛出因此f.flatMap(x.map)不安全而且可以(重新)抛出并且必须被调用时try.