在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
}
此函数的版本与第一个版本相同(并且更详细),但它会编译。
func function2<T, U>(f: Optional<T -> U>, x: Optional<T>) -> Optional<U> {
return f.flatMap { g in
x.map(g)
}
}
答案 0 :(得分:6)
这些版本不完全相同,我解释原因。
假设您具有rethrows
的函数,因为它接受抛出函数作为参数:
func a(x: () throws -> ()) rethrows {
try x()
}
所以a(x)
仅在x()
抛出时抛出。
如果你有函数b
抛出:
func b() throws {
}
然后你必须通过try:
来调用a(b)
try a(b)
a(b) // gives "Call can throw but is not marked with 'try'"
但是如果你传递给a
没有投掷功能:
func c() {
}
然后Swift编译器足够聪明,可以确定x()
函数体中的a
实际上没有抛出,它只允许调用a(c)
:
a(c) // it's ok
这是因为:
throws关键字是函数类型的一部分,也是非throwing的一部分 函数是抛出函数的子类型。因此,您可以使用 非投掷功能与投掷功能相同。
回到你的例子。
Optional.flatMap()
定义为:
public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?
在您的示例中f.flatMap
的类型为((T -> U) throws -> U?) rethrows -> U?
。
你看到它重新抛出,因为它接受throw函数参数,并且必须使用try
调用,除非f
具有类型Wrapped -> U?
并且不抛出。
Optional.map
定义为:
public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
因此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
调用。