Swift-23-异常处理和程序预处理

异常处理

你用过的软件是否经常崩溃或者做一些出乎你意料的事情?大部分情况下,这些问题是不正确的错误处理造成的。错误处理是软件开发中的幕后英雄:没人认为它重要;如果做好了,没人会注意到。同时它又非常关键:如果没做好,软件的用户肯定会注意到(而且会抱怨)。本章会探索Swift提供的捕获和处理错误的工具。

在Swift中也异常分为需查和不需查异常两类,但一般称为可恢复的错误和不可恢复的错误。一个异常的例子

var position: String.CharacterView.Index

expression failed to parse:
error: MyPlayground.playground:16:26: error: 'CharacterView' is unavailable: Please use String directly
    var position: String.CharacterView.Index    

语法格式

do{
    try  //指定可能会出现问题的代码,可以存在多个try
}
catch{ //可以存在多个catch
}

自定义异常

下面是一个综合的例子,包括自定义异常类型,以及如何抛出异常。

class Lexer {
    enum Error: Swift.Error {
        case invalidCharacter(Character)
    }
}    

手功抛出异常

需要用到关键字 throw

class Lexer {
    enum Error: Swift.Error {
        case invalidCharacter(Character)
    }

    func lex() throws -> [Token] { //Token为一自定义的枚举对象
        var tokens = [Token]()
        throw Lexer.Error.invalidCharacter(nextCharacter)
        return tokens
    }
}

稍复杂一点的例子

class Parser {
    enum Error: Swift.Error {
        case unexpectedEndOfInput
        case invalidToken(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 {
        while let token = getNextToken() {
            switch token {
            case .plus:
                let nextNumber = try getNumber()
                value += nextNumber
            case .number:
                throw Parser.Error.invalidToken(token)
            }
        }

        return value
    }
}

捕获异常

定义一个自定义的异常类型,需要用到关键字catch

class Parser {
    enum Error: Swift.Error {
        case unexpectedEndOfInput
        case invalidToken(Token)
    }
}    

一个综合的例子

//Lexer为自定义的类,实现暂时可忽略
func evaluate(_ input: String) {
    let lexer = Lexer(input: input)

    do {
        let tokens = try lexer.lex() //try

        let parser = Parser(tokens: tokens)
        let result = try parser.parse() //try
    } 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 { //通用异常捕获,而且这行必须要不,这是swift一个强制规定
        print("An error occurred: \(error)")
    }
}

测试代码

evaluate("10 + 3 + 5")

//输出如下
expression failed to parse:
error: exception.xcplaygroundpage:141:17: error: cannot find 'Lexer' in scope
    let lexer = Lexer(input: input)
                ^~~~~

error: exception.xcplaygroundpage:147:22: error: cannot find 'Parser' in scope
        let parser = Parser(tokens: tokens)
                     ^~~~~~

error: exception.xcplaygroundpage:150:13: error: cannot find 'Lexer' in scope
    } catch Lexer.Error.invalidCharacter(let character) {
            ^~~~~

error: exception.xcplaygroundpage:152:13: error: cannot find 'Parser' in scope
    } catch Parser.Error.unexpectedEndOfInput {
            ^~~~~~

error: exception.xcplaygroundpage:154:13: error: cannot find 'Parser' in scope
    } catch Parser.Error.invalidToken(let token) {
            ^~~~~~

不可查异常

  • try!:如果遇到错误则强制抛出异常,它可以不放在do{}中,比如:
//实例化一个Lexer
let lexInstance = Lexer()
//如果 lexInstance.lex() 代码出现了错误,则无法捕获,整个程序就会退出。
let lexToken = try!lexInstance.lex()

异常忽略

  • try?:如果遇到错误则可以忽略异常,它可以不放在do{}中,比如:
let lexInstance = Lexer()
guard let lexToken = try? lexInstance.lex() else{
    return
}

上面这行代码会在异常时返回nil,注意处理nil的情况

if lexToken == nil {

}

程序预处理

typealias 设置别名

下面的代码表示把系统提供的Double重新命名为Velocity,这样系统中可以同时使用不同的关系字来表示Double的浮点数了。

typealias Velocity = Double

//使用
var dou:Velocity = 12;

typealias 的位置不固定,可以定义在类外面,也可以定义在类里面,比如:

class Accountant {
    typealias NetWorthChanged = (Double) -> Void

    var netWorthChangedHandler: NetWorthChanged? = nil

    var netWorth: Double = 0.0 {
        didSet {
            netWorthChangedHandler?(netWorth)
        }
    }

    func gained(_ asset: Asset, completion: () -> Void) {
        netWorth += asset.value
        completion()
    }
}

相关推荐

  1. Swift-23-异常处理程序预处理

    2024-04-20 15:54:01       41 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-20 15:54:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-20 15:54:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-20 15:54:01       82 阅读
  4. Python语言-面向对象

    2024-04-20 15:54:01       91 阅读

热门阅读

  1. ARM Cortex-M处理器中的SysTick定时器简介

    2024-04-20 15:54:01       27 阅读
  2. 解释器模式:构建领域特定语言的强有力工具

    2024-04-20 15:54:01       39 阅读
  3. Scala详解(5)

    2024-04-20 15:54:01       29 阅读
  4. OpenXR面部跟踪接口与VIVE OpenXR扩展详细解析

    2024-04-20 15:54:01       38 阅读
  5. 【微服务】Tomcat启动闪退问题解决方法

    2024-04-20 15:54:01       26 阅读
  6. VSCode+Anaconda+Python使用教程

    2024-04-20 15:54:01       36 阅读