Swift 3 errors with additional data

流过昼夜 提交于 2019-12-20 04:29:14

问题


In Swift 3, what is the recommended way to put (potentially lots of) additional information in an error/exception that the catcher can use to solve/handle the problem? In all the examples I've seen, they use enums with associated values, and that seems overly cumbersome/verbose for lots of information.

Specifically, I am writing a simple parser and want a place to store the affected line and column numbers (and potentially other information in the future), but without requiring that every handler explicitly declare those as associated values, as that would be a burden on the caller.

At this point I can basically see two ways of doing this, neither of which seems particularly elegant and both of which require defining two different things:

  1. Define an outer enum error that represents the type of error, and for each case accept a parameter that is an object that contains the additional exception details, or
  2. Use the object as the actual Error and pass in a case from an enum to its constructor to represent the actual error condition.

Both of these feel somewhat unclean to me though as they take two separate concepts to represent a simple idea, an error, and I'm just wondering if there's a nicer way to do this.

Are there any conventions or recommended ways to handle errors that need to contain potentially lots of additional information?


回答1:


I don't know if there is a "recommended" way, perhaps someone else can answer that or provide a better solution.

But one possible approach would be to use a struct (with properties) as the error type and use optional properties for values which need not be provided. Example:

struct ParserError: Error {
    enum Reason {
        case invalidCharacter
        case unexpectedEOF
    }
    let reason: Reason
    let line: Int?
    let column: Int?

    init(reason: Reason, line: Int? = nil, column: Int? = nil) {
        self.reason = reason
        self.line = line
        self.column = column
    }
}

One might also want to adopt the LocalizedError protocol to provide sensible error descriptions even if the concrete error type is not known by the catcher (compare How to provide a localized description with an Error type in Swift?):

extension ParserError: LocalizedError {
    public var errorDescription: String? {
        var description: String
        switch reason {
        case .invalidCharacter:
            description = "Invalid Character in input file"
        case .unexpectedEOF:
            description = "Unexpected end of file"
        }
        if let line = line {
            description += ", line \(line)"
        }
        if let column = column {
            description += ", column \(column)"
        }
        return description
    }
}

Usage example:

func parse() throws {
    // Throw error with line number, but without column:
    throw ParserError(reason: .invalidCharacter, line: 13)
}

do {
    try parse()
} catch let error {
    print(error.localizedDescription)
}

Output:

Invalid Character in input file, line 13


来源:https://stackoverflow.com/questions/41202869/swift-3-errors-with-additional-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!