如何在swift中实现自定义错误抛出语法?

如何在swift中实现自定义错误抛出语法?,swift,error-handling,syntax,syntax-error,Swift,Error Handling,Syntax,Syntax Error,我希望实现以下目标: throwingFunction()??.doStuff() /* if throwingFunction throws an error: print the error else returns an object with the doStuff() Method */ 我不知道该从哪里查找关于如何实现do、try、catch的示例。说明如何使用已经实现的错误处理方法。为了清楚起见,我想用上述语法实现自定义错误处理 比如: precede

我希望实现以下目标:

throwingFunction()??.doStuff()
/*  if throwingFunction throws an error:
     print the error
  else 
    returns an object with the doStuff() Method 
*/
我不知道该从哪里查找关于如何实现do、try、catch的示例。说明如何使用已经实现的错误处理方法。为了清楚起见,我想用上述语法实现自定义错误处理

比如:

precedencegroup Chaining {
    associativity: left
}

infix operator ?? : Chaining

extension Result {
    
  // ERROR: Unary operator implementation must have a 'prefix' or 'postfix' modifier
    static func ??(value: Result<Success, Failure>) -> Success? { 
        switch value {
        case .success(let win):
            return win
        case .failure(let fail):
            print(fail.localizedDescription)
            return nil
        }
    }
}

您可以定义一个后缀运算符,该运算符将抛出闭包作为左操作数??已定义为中缀运算符,因此必须选择其他名称:

postfix operator <?>

postfix func <?><T>(expression: () throws -> T) -> T? {
    do {
        return try expression()
    } catch {
        print(error)
        return nil
    }
}
现在你可以打电话了

let result = throwingFunc<?>
let res = Result(catching: throwingFunc)<?>
或者用链子把它拴起来

let result = (throwingFunc<?>)?.doStuff()
let res = (Result(catching: throwingFunc)<?>)?.doStuff()

您可以定义一个后缀运算符,该运算符将抛出闭包作为左操作数??已定义为中缀运算符,因此必须选择其他名称:

postfix operator <?>

postfix func <?><T>(expression: () throws -> T) -> T? {
    do {
        return try expression()
    } catch {
        print(error)
        return nil
    }
}
现在你可以打电话了

let result = throwingFunc<?>
let res = Result(catching: throwingFunc)<?>
或者用链子把它拴起来

let result = (throwingFunc<?>)?.doStuff()
let res = (Result(catching: throwingFunc)<?>)?.doStuff()

如果你不真的使用apple/swift并创建你自己的编译器版本,你几乎不可能做到这一点。。。以下是我的尝试:

首先,我注意到期望结果的第二部分,doStuff看起来完全像一个可选的链接表达式。我以为我可以做个后缀?返回可选值的运算符。但事实证明,我不能申报?接线员:

postfix operator ? // error
所以我用了一个视觉上相似的角色来代替。抛出函数的类型是throws->Void,我使用了@autoclosure以便可以省略{}:

typealias ThrowingFunction<T> = () throws -> T

postfix operator ‽
postfix func ‽<T>(lhs: @autoclosure ThrowingFunction<T>) -> T? {
    switch Result(catching: lhs) {
    case .failure(let error):
        print(error.localizedDescription)
        return nil
    case .success(let t):
        return t
    }
}

// Usage:
func f() throws -> Int {
    throw URLError(URLError.badURL)
}

// You have to use it like this :(
(try f()‽)
(try f()‽)?.description
要使其他算术的函数不经过尝试就可以工作,您需要为每个算术创建一个‽的实现,这很糟糕

但括号必须在那里,因为Swift解析运算符的方式:

然后,我尝试采用您尝试的方法,使用关键路径:

func ??<T, U>(lhs: @autoclosure ThrowingFunction<T>, rhs: KeyPath<T, U>) -> U? {
    switch Result(catching: lhs) {
    case .failure(let error):
        print(error.localizedDescription)
        return nil
    case .success(let t):
        return t[keyPath: rhs]
    }
}

func f() throws -> Int {
    throw URLError(URLError.badServerResponse)
}
你不能不试一下

此外,这种反冲是键路径语法的一个组成部分,您只能将其用于键路径,而不能用于方法:

总结 您不能这样做,因为:

你不能超载吗? 你不能放一个?因为它将被解析为可选链接 除非你能满足每一种需求,否则你必须写一篇文章。
如果你不真的使用apple/swift并创建你自己的编译器版本,你几乎不可能做到这一点。。。以下是我的尝试:

首先,我注意到期望结果的第二部分,doStuff看起来完全像一个可选的链接表达式。我以为我可以做个后缀?返回可选值的运算符。但事实证明,我不能申报?接线员:

postfix operator ? // error
所以我用了一个视觉上相似的角色来代替。抛出函数的类型是throws->Void,我使用了@autoclosure以便可以省略{}:

typealias ThrowingFunction<T> = () throws -> T

postfix operator ‽
postfix func ‽<T>(lhs: @autoclosure ThrowingFunction<T>) -> T? {
    switch Result(catching: lhs) {
    case .failure(let error):
        print(error.localizedDescription)
        return nil
    case .success(let t):
        return t
    }
}

// Usage:
func f() throws -> Int {
    throw URLError(URLError.badURL)
}

// You have to use it like this :(
(try f()‽)
(try f()‽)?.description
要使其他算术的函数不经过尝试就可以工作,您需要为每个算术创建一个‽的实现,这很糟糕

但括号必须在那里,因为Swift解析运算符的方式:

然后,我尝试采用您尝试的方法,使用关键路径:

func ??<T, U>(lhs: @autoclosure ThrowingFunction<T>, rhs: KeyPath<T, U>) -> U? {
    switch Result(catching: lhs) {
    case .failure(let error):
        print(error.localizedDescription)
        return nil
    case .success(let t):
        return t[keyPath: rhs]
    }
}

func f() throws -> Int {
    throw URLError(URLError.badServerResponse)
}
你不能不试一下

此外,这种反冲是键路径语法的一个组成部分,您只能将其用于键路径,而不能用于方法:

总结 您不能这样做,因为:

你不能超载吗? 你不能放一个?因为它将被解析为可选链接 除非你能满足每一种需求,否则你必须写一篇文章。 下面是一个示例用法

enum TestMeError: Error {
    case first
}

extension Int {
    func printWin() {
        print("we did it!")
    }
}

func testMe() -> ErrorAlt<Int> {
    if true {
        return .error(TestMeError.first)
    } else {
        return .preferred(40)
    }
}

// USAGE
testMe()*
下面是一个示例用法

enum TestMeError: Error {
    case first
}

extension Int {
    func printWin() {
        print("we did it!")
    }
}

func testMe() -> ErrorAlt<Int> {
    if true {
        return .error(TestMeError.first)
    } else {
        return .preferred(40)
    }
}

// USAGE
testMe()*

请用中文读Guide@vadian,请看我更新的问题。你看了类型了吗?类似ResultCatch:throwingFunction.mapdoStuff.get这样的东西应该可以做到这一点。那么,您想创建自己版本的Swift编译器来实现这一点吗?@Sweeper,更新了问题。我在找这样的东西。或者一个采用错误抛出函数的infex运算符的任何实现的示例。请阅读语言Guide@vadian,请看我更新的问题。你看了类型了吗?类似ResultCatch:throwingFunction.mapdoStuff.get这样的东西应该可以做到这一点。那么,您想创建自己版本的Swift编译器来实现这一点吗?@Sweeper,更新了问题。我在找这样的东西。或者是采用错误抛出函数的infex运算符的任何实现的示例。我正在尝试想出一种方法来执行throwingFunc而不是ResultCaching:throwingFunc@ScottyBlades:现在好多了?@ScottyBlades:你能解释一下为什么需要第二个自定义中缀操作符吗?返回一个可选值,以便您可以使用“内置”可选链接将其链接。@ScottyBlades:您可以定义一个中缀运算符func表达式:throws->T,op:T->R->R?以同样的方式,但与简单的正交特征相比有什么优势?@ScottyBlades:Done。我在想一种方法来进行throwingFunc而不是ResultCaching:throwingFunc@ScottyBlades:现在好多了?@ScottyBlades:你能解释一下为什么需要第二个自定义中缀操作符吗?返回一个可选的链接,以便您可以使用“内置”可选链接将其链接
g、 @ScottyBlades:您可以定义一个中缀运算符func表达式:throws->T,op:T->R->R?以同样的方式,但与简单的正交特征相比有什么优势?@ScottyBlades:完成。一点也不讽刺。我可能会花一年的时间来尝试一些东西,以达到你在1小时内达到的探索水平。它给了我一些想法,也给了我面包屑。@ScottyBlades好吧,很抱歉我怀疑了你:看起来它可能也给了@Martin一个想法。我觉得很幸运,你们能在早上5:53和我一起探索这些想法,哈哈。@ScottyBlades:我在更新我的答案之前没有读过这篇文章,但这些想法似乎非常相似。@Sweeper,我把它分成了一个部分。一点也不讽刺。我可能会花一年的时间来尝试一些东西,以达到你在1小时内达到的探索水平。它给了我一些想法,也给了我面包屑。@ScottyBlades好吧,很抱歉我怀疑了你:看起来它可能也给了@Martin一个想法。我感到很幸运,你们能在早上5:53和我一起探索这些想法,哈哈。@ScottyBlades:我在更新我的答案之前没有读过这篇文章,但这些想法似乎非常相似。@Sweeper,我把这篇文章分成了两部分。