理解Swift中的关键字throw和rethrows

Swift中throwrethrows关键字用于异常处理(Error handling),都是用在函数中,可以简单理解为throw让函数或者方法可能出现的异常得到处理(比如用do-catch处理),而rethrows只是传递throw,本身没有针对函数或方法,下面详细解释一下:

throw

throws关键字首先用在函数申明中,放在返回类型的前面,比如标准库中map的函数签名:

func map<T>(_ transform: (Int) throws -> T) rethrows -> [T]

然后在函数内部,如果出现可能的异常,就可以throw这个异常,通常可以用一个枚举来代表一类异常,这个枚举可以实现Error协议,比如:

enum TestError: Error {
    case errorOne(Int)
    case errorTwo(String)
    case errorThree
    case errorUnknown
}

func testThrow(num: Int) throws -> String {
    switch num {
    case 1:
        throw TestError.errorOne(1)
    case 2:
        throw TestError.errorTwo("2")
    case 3:
        throw TestError.errorThree
    case 4:
        throw TestError.errorUnknown
    default:
        return "No Error"
    }
}

这样,通过throw函数中可能出现的异常,让函数反馈错误,强制调用这个函数的程序员处理所有可能的错误,减少维护成本。

下面使用do-catch来处理可能的异常:

do {
    let testResult: String = try testThrow(num: 2)
    print(testResult)  // Will no print
} catch TestError.errorOne(let num) {
    print(num)  // 1
} catch TestError.errorTwo(let str) {
    print(str)  // 2
} catch TestError.errorThree {
    print(TestError.errorThree)  // errorThree
} catch let err {
    print(err)  // errorUnknown
}
//  2

rethrows

rethrows关键字只起到传递异常的作用,在一个函数或者方法中,调用一个会throw的函数,就可以通过rethrows传递可能的异常,接上面的例子:

func testRethrow(testThrowCall: (Int) throws -> String, num: Int) rethrows -> String {
    try testThrowCall(num)
}

观察函数申明,其实就是有一个会throw函数作为参数,然后在返回类型前面添加关键字rethrows,函数内部直接调用那个会throw的函数,传递可能的异常,处理rethrows的函数或方法就和处理throw的函数或方法一样:

do {
    let testResult: String = try testRethrow(testThrowCall: testThrow, num: 4)
    print(testResult)  // Will no print
} catch TestError.errorOne(let num) {
    print(num)  // 1
} catch TestError.errorTwo(let str) {
    print(str)  // 2
} catch TestError.errorThree {
    print(TestError.errorThree)  // errorThree
} catch let err {
    print(err)  // errorUnknown
}
//  errorUnknown

总结

throw在函数或者方法中抛出异常,让调用者必须明确地处理可能的异常,rethrows本身并不抛出异常或者处理异常,其只起到传递异常的作用,最后回到标准库中的map函数,综合上述举个例子:

enum NegativeError: Error {
    case negative
}

let nums = [-1, 1, 2, 3, 4]

do {
    let strNums = try nums.map { (num) throws -> String in
        if num >= 0 {
            return String(num)
        } else {
            throw NegativeError.negative
        }
    }
    print(strNums)  // Will no print
} catch let err {
    print(err)
}
// negative

这里在map的函数参数中使用了throw,当元素小于0时抛出异常

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342