88

在搜索了一些参考资料以弄清楚之后,-不幸的是-我找不到有用的-简单的-关于理解和之间差异的throws描述rethrows。当试图理解我们应该如何使用它们时,这有点令人困惑。

我要提一下,我对 -default- 有点熟悉,throws它最简单的形式用于传播错误,如下所示:

enum CustomError: Error {
    case potato
    case tomato
}

func throwCustomError(_ string: String) throws {
    if string.lowercased().trimmingCharacters(in: .whitespaces) == "potato" {
        throw CustomError.potato
    }

    if string.lowercased().trimmingCharacters(in: .whitespaces) == "tomato" {
        throw CustomError.tomato
    }
}

do {
    try throwCustomError("potato")
} catch let error as CustomError {
    switch error {
    case .potato:
        print("potatos catched") // potatos catched
    case .tomato:
        print("tomato catched")
    }
}

到目前为止一切顺利,但是在以下情况下会出现问题:

func throwCustomError(function:(String) throws -> ()) throws {
    try function("throws string")
}

func rethrowCustomError(function:(String) throws -> ()) rethrows {
    try function("rethrows string")
}

rethrowCustomError { string in
    print(string) // rethrows string
}

try throwCustomError { string in
    print(string) // throws string
}

到目前为止我所知道的是,当调用一个throws必须由 a 处理的函数时try,与rethrows. 所以呢?!在决定使用throwsor时我们应该遵循什么逻辑rethrows

4

2 回答 2

203

来自Swift 书中的“声明” :

重新抛出函数和方法

可以使用rethrows关键字声明函数或方法,以指示仅当其函数参数之一引发错误时才引发错误。这些函数和方法称为 重新抛出函数重新抛出方法。重新抛出函数和方法必须至少有一个抛出函数参数。

一个典型的例子是map方法:

public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]

如果map使用非抛出转换调用,它本身不会抛出错误,并且可以在没有 的情况下调用try

// Example 1:

let a = [1, 2, 3]

func f1(n: Int) -> Int {
    return n * n
}

let a1 = a.map(f1)

但是如果map用 throwing 闭包调用,那么它本身可以抛出并且必须用try:

// Example 2:

let a = [1, 2, 3]
enum CustomError: Error {
    case illegalArgument
}

func f2(n: Int) throws -> Int {
    guard n >= 0 else {
        throw CustomError.illegalArgument
    }
    return n*n
}


do {
    let a2 = try a.map(f2)
} catch {
    // ...
}
  • 如果map声明为thenthrows而不是,即使在示例 1 中,rethrows您也必须使用它来调用它try,这“不方便”并且使代码变得不必要。
  • 如果map没有声明,throws/rethrows则不能像示例 2 中那样使用抛出闭包来调用它。

Swift 标准库中的其他方法也是如此,它们采用函数参数:filter()index(where:)等等forEach()

在你的情况下,

func throwCustomError(function:(String) throws -> ()) throws

表示即使使用非抛出参数调用也可能抛出错误的函数,而

func rethrowCustomError(function:(String) throws -> ()) rethrows

表示仅在使用抛出参数调用时抛出错误的函数。

粗略地说,rethrows适用于不会“自行”抛出错误的函数,而只会从其函数参数中“转发”错误。

于 2017-04-09T09:37:02.143 回答
16

只是在马丁的回答中添加一些东西。与抛出函数具有相同签名的非抛出函数被认为是sub-type抛出函数的一个。这就是为什么 rethrows 可以确定它是哪一个,并且仅try在 func 参数也抛出时才需要,但仍然接受不抛出的相同函数签名。这是一种方便的方法,只需要在 func 参数抛出时使用 do try 块,但函数中的其他代码不会抛出错误。

于 2017-04-09T12:38:44.087 回答