从存储的抛出函数抛出错误

发布于 2025-01-13 03:37:05 字数 323 浏览 1 评论 0原文

我有一个抛出完成块处理程序的数组:

typealias CompletionBlock = (MyType) throws -> Void

private var handlers: [CompletionBlock] = []

我希望稍后能够调用它们并抛出这样的错误:

for handler in handlers {
    handler(throw myError)
}

但是,这不起作用,因为它期望我将 MyType 传递给处理程序,而不是错误。我该怎么做?

I have an array of throwing completion block handlers:

typealias CompletionBlock = (MyType) throws -> Void

private var handlers: [CompletionBlock] = []

I want to be able to recall them later on and throw an error like this:

for handler in handlers {
    handler(throw myError)
}

However, that doesn't work because it's expecting me to pass MyType to the handler, not an error. How can I do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜巴黎 2025-01-20 03:37:05

你的问题有点模糊,但我假设你的意思是你希望处理程序接受抛出函数的结果。这是可能的,我将展示如何实现,但这并不是您想要的。

“抛出函数的结果”可以通过调用一个调用抛出函数的函数来表达:

typealias CompletionBlock = (() throws -> MyType) -> Void

以您描述的方式抛出错误:

let result: () throws -> MyType = { throw MyError() }

for handler in handlers {
    handler(result)
}

处理程序将如下所示:

func h(result: () throws -> MyType) {
    do {
        let myType = try result()
        // ...
    } catch {
        // ...
    }
}

但这不是一个很好的设计。最重要的是它多次执行result。相反,您希望传递抛出函数的 Result

typealias CompletionBlock = (Result<MyType, Error>) -> Void

let f: () throws -> MyType = { throw MyError() }

let result = Result(catching: f)

for handler in handlers {
    handler(result)
}

更常见的做法是:

let result = Result {
    // Do various operations that might throw
    return value
}

您还可以使用 try result.get() 将 Result 转换回 throws。因此,您可以轻松地在 Result 和 throws 之间移动,无论您喜欢什么地方。结果最适合保存。投掷最适合跟注。你可以两者兼得。

(当然,您还应该展望未来并探索用 async/await 替换完成处理程序,但有很多原因您可能不会立即这样做,因此 Result 将在相当长的一段时间内成为一个重要工具。)

Your question is a bit vague, but I'm going to assume you mean that you want the handlers to accept the result of a throwing function. That's possible, and I'll show how, but it's not quite what you want.

"The result of a throwing function" can be expressed by calling a function that calls a throwing function:

typealias CompletionBlock = (() throws -> MyType) -> Void

Throwing an error in the way you've described like this:

let result: () throws -> MyType = { throw MyError() }

for handler in handlers {
    handler(result)
}

A handler would then look like:

func h(result: () throws -> MyType) {
    do {
        let myType = try result()
        // ...
    } catch {
        // ...
    }
}

But this is not a great design. Most importantly it executes result many times. Instead you want to pass the Result of a throwing function:

typealias CompletionBlock = (Result<MyType, Error>) -> Void

let f: () throws -> MyType = { throw MyError() }

let result = Result(catching: f)

for handler in handlers {
    handler(result)
}

The more common look for this is along these lines:

let result = Result {
    // Do various operations that might throw
    return value
}

You can also convert back from Result to a throws using try result.get(). So you can easily move between Result and throws wherever you like. Result is best for storing. Throws is best for calling. You can have both.

(And of course, you should also be looking to the future and exploring replacing completion handlers with async/await, but there are many reasons you might not do that right away, so Result will be an important tool for quite some time.)

寂寞陪衬 2025-01-20 03:37:05

您试图通过强制存储闭包抛出错误(无论其输入如何)来更改它的行为。你不能那样做。

您将 CompletionBlock 标记为 throws 的事实仅意味着闭包本身可能会抛出异常。但是,您不能强制它抛出,因为您只能将 MyType 类型的输入参数传递给它。

此外,强制抛出闭包是没有意义的,因为无论如何您都需要处理从调用站点抛出的错误。所以你可以简单地从调用站点抛出错误。

或者,如果您需要闭包本身来处理错误,则应该更改闭包以接受Result,并防止注入中的.failure ,闭包本身可能会抛出异常。

typealias CompletionBlock = (Result<MyType, MyError>) throws -> Void

private var handlers: [CompletionBlock] = []

for handler in handlers {
    handler(.failure(myError))
}

You are trying to change the behaviour of a stored closure by forcing it to throw an error regardless of its input. You cannot do that.

The fact that you marked CompletionBlock as throws only means that the closure itself might throw. However, you cannot force it to throw, since you can only pass an input argument of type MyType to it.

Moreover, there's no point in enforcing a closure to throw, since you need to handle the error thrown from the call-site anyways. So you can just simply throw the error from the call site.

Alternatively, if you need the closure itself to handle an error, you should change the closure to accept a Result and in case .failure in injected, the closure itself could throw.

typealias CompletionBlock = (Result<MyType, MyError>) throws -> Void

private var handlers: [CompletionBlock] = []

for handler in handlers {
    handler(.failure(myError))
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文