【问题标题】:How to use Result type to store success/failure states in Swift如何使用 Result 类型在 Swift 中存储成功/失败状态
【发布时间】:2022-01-28 02:08:40
【问题描述】:

在关于错误处理/异步编程的章节中,有一个关于表达式评估器的示例和关于为以后存储失败结果的代码 - 下面的代码,函数评估后的行。这部分确实会抛出更多错误,想请问您是否可以帮助澄清这些。正如我被告知的那样,我将 lex() 方法返回类型更改为 Result。并返回成功或失败。 .success(tokens) 或 .failure(.invalidCharacter(nextCharacter)),但是后来没有用。还尝试注释掉与 Parser 相关的所有行。如果你能建议。

在最后几行中,我根据大家的意见修改了代码,感谢您的帮助。更改已注释。

   enum Token: CustomStringConvertible {
    case number (Int)
    case plus
    
    var description: String {
        switch self {
        case .number (let n):
            return "Number: \(n)"
        case .plus:
            return "Symbol: +"
        }
    }
}

class Lexer {
    enum Error: Swift.Error {
        case invalidCharacter (Character)
    }
    
    let input: String
    var position: String.Index
    
    init(input: String) {
        self.input = input
        self.position = input.startIndex
    }
    
    func peek() -> Character? {
        guard position < input.endIndex else {
            return nil
        }
        return input[position]
    }
    
    func advance() {
        assert(position < input.endIndex, "Cannot advance past endIndex!")
        position = input.index(after: position)
    }
    
    func getNumber() -> Int {
        var value = 0
        
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0" ... "9":
                let digitValue = Int(String(nextCharacter))!
                value = 10*value + digitValue
                advance()
            default:
                return value
            }
        }
        return value
    }
    
    func lex() throws -> [Token] { // changed to [Token]
        var tokens = [Token]()
        
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0" ... "9":
                let value = getNumber()
                tokens.append(.number(value))
            case "+":
                tokens.append(.plus)
                advance()
            case " ":
                advance()
            default:
                throw Lexer.Error.invalidCharacter(nextCharacter)
                // .failure(.invalidCharacter(nextCharacter)) did not work here
            }
        }
        return tokens // changed to tokens
    }
}

func evaluate(_ input: String) {
    print("Evaluating: \(input)")
    let lexer = Lexer(input: input)
    do {
        let tokens = try lexer.lex()
        print("Lexer output: \(tokens)")
    
       // let parser = Parser(tokens: tokens)
       // let result = try parser.parse()
       // print("Parser output: \(result)")
    } catch Lexer.Error.invalidCharacter(let character) {
        print("Input contained an invalid character: \(character)")
    // } catch Parser.Error.unexpectedEndOfInput {
        // print("Unexpected end of input during parsing")
    // } catch Parser.Error.invalidToken(let token) {
       //  print("Invalid token during parsing: \(token)")
    } catch {
        print("An error occured: \(error)")
    }
}
/*
class Parser {
    enum Error: Swift.Error {
        case unexpectedEndOfInput
        case invalidToken(Token)
    }
   
    let tokens: [Token] // [Token]
    var position = 0
    
    init(tokens: [Token]) {
        self.tokens = tokens // tokens
    }
    
    func getNextToken() -> Token? {
        guard position < tokens.count else {
            return nil
        }
        
        let token = tokens[position]
        position += 1
        return token
    }
    
    func getNumber() throws -> Int {
        guard let token = getNextToken() else {
            throw Parser.Error.unexpectedEndOfInput
        }
        
        switch token {
        case .number(let value):
            return value
        case .plus:
            throw Parser.Error.invalidToken(token)
        }
    }
    
    func parse() throws -> Int {
        var value = try getNumber()
        
        while let token = getNextToken() {
            switch token {
            case .plus:
                let nextNumber = try getNumber()
                value += nextNumber
            case .number:
                throw Parser.Error.invalidToken(token)
            }
        }
        return value
    }
}
*/

// evaluate("10 + 1")

/*
let lexer = Lexer(input: "1 + 2")
let tokensResult = Result { try lexer.lex() }
print(tokensResult)
*/

/*
let lexer = Lexer(input: "1 + 2 + 3")
let tokensResult = Result { try lexer.lex() } // Result<Success, Failure>' cannot be constructed because it has no accessible initializers

enum Result<Success, Failure> where Failure : Error {
    case .success(Success) // Extraneous '.' in enum 'case' declaration
    case .failure(Failure) // Extraneous '.' in enum 'case' declaration
}

switch tokensResult {
case let .success(tokens):
    print("Found \(tokens.count) tokens \(tokens)")
case let .failure(error):
    print("Could not lex \(lexer.input): \(error)")
}

let numbersResult: Result<[Int],Error> = tokensResult.map {
      tokens.compactMap { token in // Cannot find 'tokens' in scope
          switch token {
          case let .number(digit): return digit
          default: return nil
          }
      }
}

func extractNumbers(from result: Result<[Int],Error>) throws -> [Int] {
        return try result.get() // Value of type 'Result<[Int], Error>' has no member 'get'
    }
*/

let lexer = Lexer(input: "1 + 7")
let tokensResult = Result { try lexer.lex() }
var tokens = [Token]() // added

// deleted redeclaration of Result

switch tokensResult {
case let .success(tokens):
    print("Found \(tokens.count) tokens \(tokens)")
case let .failure(error):
    print("Could not lex \(lexer.input): \(error)")
}

// before error: Contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored, fixed by: insert _ in

let numbersResult: Result<[Int],Error> = tokensResult.map { _ in
      tokens.compactMap { token in
          switch token {
          case let .number(digit): return digit
          default: return nil
          }
      }
}

func extractNumbers(from result: Result<[Int],Error>) throws -> [Int] {
        return try result.get()
    }

【问题讨论】:

    标签: swift xcode asynchronous error-handling closures


    【解决方案1】:

    我认为您需要更多地阅读Result 类型以及如何使用它,因为上面有一些非常奇怪的代码。

    这是我清理后的代码版本,没有重新定义 Result 和处理.success的正确方法

    let lexer = Lexer(input: "1 + 2 + 3")
    let tokensResult = try lexer.lex()
    
    var tokens =  [Token]()
    switch tokensResult {
    case let .success(result):
        print("Found \(tokens.count) tokens \(tokens)")
        tokens = result
    case let .failure(error):
        print("Could not lex \(lexer.input): \(error)")
    }
    
    let numbersResult = tokens.compactMap { token in
        switch token {
        case let .number(digit): return digit
        default: return nil
        }
    }
    

    【讨论】:

    • 感谢@Joakim 的帮助,我删除了重新声明,在 tokensResult.map { 之后添加了 var tokens = [Token]() 和 _ 根据编辑后的答案。当然我学习和锻炼更多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-10
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 2023-01-08
    相关资源
    最近更新 更多