Swift中的throws和rethrows之间有什么区别?

时间:2017-04-09 09:16:34

标签: swift error-handling try-catch throws rethrow

在搜索了一些参考资料后,很明显 - 我找不到有用的和简单的描述来理解throwsrethrows之间的差异。当试图理解我们应该如何使用它时,这有点令人困惑。

我想提一下,我很熟悉-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必须由try处理的函数,与rethrows不同。所以呢?!在决定使用throwsrethrows

时,我们应该遵循什么逻辑?

2 个答案:

答案 0 :(得分:133)

来自Swift书中的"Declarations"

  

重新定义函数和方法

     

可以使用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,那么它本身就可以抛出 并且必须使用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被声明为throws而不是rethrows,那么您会 即使在示例1中也必须使用try调用它, 这是&#34;不方便&#34;并且不需要代码。
  • 如果宣布map没有throws/rethrows,那么你就不能 如示例2所示,使用抛出闭包来调用它。

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

在你的情况下,

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

表示即使调用了也可以抛出错误的函数 一个非投掷的论点,而

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

表示仅在使用a调用时才会抛出错误的函数 抛出争论。

粗略地说,rethrows用于不抛出的函数 错误&#34;他们自己&#34;,但只有&#34;转发&#34;他们的功能错误 参数。

答案 1 :(得分:12)

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

相关问题