如何将 try-catch 移动到处理所有 try-catch 逻辑以及 return 错误的 class?

How do I move try-catch into a class that handles all try-catch logic but also return errors?

我正在写一个基本的玩家 wallet 管理 class 其中 Integers 被添加(贷记)或减去(借记)到玩家的钱包,其中错误被一个简单的 try-catch逻辑。

Note: It only is meant to handle Integers.

我正试图将 try-catch 逻辑抽象到这个钱包 class 中;它应该处理任何带有 creditdebit 操作、捕获错误和 return 错误(如果发现)。

有没有办法将 try-catch 内容移动到 class 但 return 的错误中?

让我们看一下这个例子:

我现在的class是这样的:

enum WalletError : Error {
    case mustBePositive
    case notEnoughFunds
}

class Wallet {
    public private(set) var balance: Int = 0

    init(amount: Int = 0) {
        self.balance = amount
    }

    func credit(amount: Int) throws {
        guard amount > 0 else {
            throw WalletError.mustBePositive
        }
        handleCredit(amount: amount)
    }

    func debit(amount: Int) throws {
        guard amount > 0 else {
            throw WalletError.mustBePositive
        }
        guard balance >= amount else {
            throw WalletError.notEnoughFunds
        }
        guard (self.balance - amount >= 0) else {
            throw WalletError.notEnoughFunds
        }
        handleDebit(amount: amount)
    }

    // MARK: (Private)

    private func handleCredit(amount: Int) {
        self.balance += amount
    }

    private func handleDebit(amount: Int) {
        self.balance -= amount
    }
}

测试借记操作,我有这个XCTest函数

func testDebit() {
    let w = Wallet()

    XCTAssertTrue(w.balance == 0)

    // Can't debit negative numbers
    XCTAssertThrowsError(try w.debit(amount: -100)) { error in
        XCTAssertEqual(error as? WalletError, WalletError.mustBePositive)
    }

    // can't debit money you don't have
    XCTAssertThrowsError(try w.debit(amount: 100)) { error in
        XCTAssertEqual(error as? WalletError, WalletError.notEnoughFunds)
    }

    // credit 0
    XCTAssertNoThrow(try w.credit(amount: 100))

    // debit [=13=] should throw error
    XCTAssertThrowsError(try w.debit(amount: 0)) { error in
        XCTAssertEqual(error as? WalletError, WalletError.mustBePositive)
    }

    // debit > balance should throw error
    XCTAssertThrowsError(try w.debit(amount: 101)) { error in
        XCTAssertEqual(error as? WalletError, WalletError.notEnoughFunds)
    }

    // debit  should be successful
    XCTAssertNoThrow(try w.debit(amount: 1))

    // balance should be 100-1 = 
    XCTAssertTrue(w.balance == 99)
}

我在这里遇到的问题是:

我写应用的时候每次都需要写try-catch块

我希望钱包 class 能够处理所有 try-catch 内容,并且只报告错误

我试过这个:

// changes to wallet class
func canCredit(amount: Int) throws -> Bool {
    guard amount > 0 else {
        throw WalletError.mustBePositive
    }
    return true
}

func credit(amount: Int) -> Error? {
    do {
        if ( try canCredit(amount: amount) ) {
            handleCredit(amount: amount)
        }
        return nil
    } catch let error {
        return error
    }
}

但是现在 XCTest 不知道抛出,我需要测试现在只有 returns true/false.

的 canCredit

此外,信用试图return错误,但我不能使用XCTAssertThrowsError()

有什么办法可以吗:

  1. 钱包class应该只负责信用、借记和验证

  2. 将我所有的 try-catch 逻辑都放到这里 class 这样我就不必一直重复 try-catch 了?

我希望我已经澄清了这个问题。

谢谢

制作函数throw并交出错误

func credit(amount: Int) throws {
    try canCredit(amount: amount)
    handleCredit(amount: amount)  
}
  • 如果 canCredit 成功,代码将转到下一行并处理信用。
  • 如果canCredit失败,接收到的错误将移交并退出函数。

您的目标似乎是将抛出的错误转换为返回的错误。这个目标似乎是错误的。抛出一种流量控制形式。抛出一个错误 你如何 "return an error" 给调用者的。首先,你不应该想要你似乎想要的东西。

不过,你一定可以做到。首先,保持 credit(amount:)debit(amount:) 方法与第一个代码示例中的方法完全相同,以便您的单元测试可以测试它们。其次,在您的 "real code" 中,不要调用这些方法。相反,调用您提供的其他 "wrapper" 方法,捕获抛出的错误并将其转换为返回的错误。

例如:

func realcredit(amount: Int) -> Error? {
    do {
        try credit(amount:amount)
        return nil
    } catch {
        return error
    }
}