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

Ahm*_*d F 64 error-handling try-catch rethrow throws swift

寻找一些参考资料后弄明白,-unfortunately-我找不到任何关于理解之间的差异有用-和简单-描述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")
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一直很好,但问题出现在:

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
}
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*n R 142

从Swift书中的"声明":

重新定义函数和方法

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

典型的例子是map方法:

public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
Run Code Online (Sandbox Code Playgroud)

如果map使用非抛出变换调用它,它本身不会抛出错误,并且可以在没有try:

// Example 1:

let a = [1, 2, 3]

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

let a1 = a.map(f1)
Run Code Online (Sandbox Code Playgroud)

但是如果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 {
    // ...
}
Run Code Online (Sandbox Code Playgroud)
  • 如果map被声明为throws代替rethrows那么你将不得不try在示例1中调用它,这是"不方便"并且不需要代码.
  • 如果map没有声明,throws/rethrows则无法使用抛出闭包调用它,如示例2所示.

同样是从雨燕标准库的其它方法取功能参数真:filter(),index(where:),forEach()和许多许多.

在你的情况下,

func throwCustomError(function:(String) throws -> ()) throws
Run Code Online (Sandbox Code Playgroud)

表示一个可以抛出错误的函数,即使使用非抛出参数调用,也可以

func rethrowCustomError(function:(String) throws -> ()) rethrows
Run Code Online (Sandbox Code Playgroud)

表示只有在使用throw参数调用时才会抛出错误的函数.

粗略地说,rethrows是针对不会"自行"抛出错误的函数,而是来自函数参数的"转发"错误.

  • 最后一句是金色的! (18认同)
  • @Honey:我没有完全理解你的意思。`rethrows`仅与带有可能会抛出的函数参数的函数一起使用。 (2认同)

Jus*_*inM 13

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