异常处理

2021/4/27 18:27:39

本文主要是介绍异常处理,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

语法错误:就平时写程序的时候会报的错误,在编译之前就得处理掉

逻辑错误:代码写错了,比如加写成-了

运行时错误 

程序员日常解决最多的错误应该就是运行时错误了,跑着跑着不知道为毛挂了,然后就开始打断点做各种调试

func divide(dividend:Int,divisor:Int) -> Int {
    return dividend / divisor
}
print(divide(dividend: 20, divisor: 0))

在非自定义错误的情况下可以做如下处理

func divide(dividend:Int,divisor:Int) -> Int? {
    if divisor == 0 {
        return nil
    }
    return dividend / divisor
}
print(divide(dividend: 20, divisor: 0))

比如返回一个可选类型,处理在0的时候返回nil,这样后面判断一下这个可选类型就好了

自定义错误

捕获到错误了之后的自定义错误

struct MyError: Error {
    var errorCode:String
}

func divide(dividend:Int,divisor:Int) throws -> Int? {
    if divisor == 0{
        throw MyError(errorCode: "除数不能是0")
    }
    return dividend / divisor
}

var result = try divide(dividend: 10, divisor: 0)
print(result)

比如这里面就是一个自定义的错误,自定义错误是一个协议,所以枚举 结构体 类都可以继承,一般来说为了省空间可以考虑枚举,因为枚举实际占用字节是1个字节,如果是要报错的字符串,也最好用结构体,实际占用8个字节,如果用类的话实际占用就大很多了,指针是8个字节,里面是类信息最起码就16个字节,元类信息占用空间更大,所以能不用类尽量别用

do-catch

上面的代码运行会报错,原因就是没有处理这个异常,Swift处理异常就是do-Catch语法

struct MyError: Error {
    var errorCode:String
}

func divide(dividend:Int,divisor:Int) throws -> Int? {
    if divisor == 0{
        throw MyError(errorCode: "除数不能是0")
    }
    return dividend / divisor
}

func fn1()
{
    do {
        try divide(dividend: 20, divisor: 0)
    } catch let myError as MyError {
        print(myError.errorCode)
    } catch
    {
        print("catch到未知错误")
    }
}
fn1()

错误链

enum MyError: Error {
    case errorCode(String)
    case outOfBounds(Int,Int)
}

func divide(dividend:Int,divisor:Int) throws -> Int? {
    if divisor == 0{
        throw MyError.errorCode("除数不能是0")
    }
    return dividend / divisor
}

func fn1() throws
{
    try divide(dividend: 20, divisor: 0)
}

func fn2() throws
{
    try fn1()
}

do {
    try fn2()
} catch let MyError.errorCode(errorCode) {
    print(errorCode)
    
}catch let MyError.outOfBounds(index,limit)
{
    print("index:\(index) out of \(limit)")
}

假如在下层函数不用处理,也可以把错误往上抛,直到主函数,不过主函数不处理就会报错了

try? try!

func divide(dividend:Int,divisor:Int) throws -> Int? {
    if divisor == 0{
        throw MyError.errorCode("除数不能是0")
    }
    return dividend / divisor
}
let result = try? divide(dividend: 10, divisor: 0)
print(result)

try?和try!的区别只在使用上面,本质就是把错误转为可选项,如果有错误就返回nil

retrows

enum MyError: Error {
    case errorCode(String)
    case outOfBounds(Int,Int)
}

func divide(dividend:Int,divisor:Int) throws -> Int {
    if divisor == 0{
        throw MyError.errorCode("除数不能是0")
    }
    return dividend / divisor
}

func fn1(fn:(Int,Int) throws -> Int, a:Int , b:Int) rethrows
{
    print(try fn(a,b))
}

do {
    try fn1(fn: divide, a: 10, b: 0)
} catch let MyError.errorCode(errorCode) {
    print(errorCode)
}

当如果传入的闭包函数有问题,这个类也不准备处理的时候就用rethrows把错误传到更上一级的函数

defer

struct LengthError:Error {
    var des:String
}
func open(path:String) -> Int
{
    print("打开")
    return 0
}
func read(length:Int,sign:Int) throws -> String
{
    if(length > 1000)
    {
        throw LengthError(des:"太长了")
    }
    return "content"
}

func close()
{
    print("关闭")
}

func readBook() throws
{
    let sign = open(path: "123")
    try read(length: 1001, sign: sign)
    close()
}
try? readBook()

假如这是个读取代码,因为长度超过了1000函数不支持,抛出异常,这种情况来说,close()就不会调用了,因为异常之后的代码就不会执行了

func readBook() throws
{
    let sign = open(path: "123")
    defer
    {
        close()
    }
    try read(length: 1001, sign: sign)
    
}

假如加上了defer就会在该作用域结束前调用,比如这个就是在readBook结束之前调用,所以即使抛出异常也会执行关闭

注意点:

func readBook() throws
{
    let sign = open(path: "123")
    defer{ print("1") }
    defer{ print("2") }
    defer{ print("3") }
    try read(length: 1001, sign: sign)
}

同一个defer是从上往下,但不同的defer先声明的执行越晚,比如上面来说结果是3,2,1



这篇关于异常处理的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程