swift2 快速的do-try-catch语法

kadbb459  于 2022-11-06  发布在  Swift
关注(0)|答案(7)|浏览(197)

我试着去理解swift 2中新的错误处理。下面是我所做的:我首先声明了一个错误枚举:

enum SandwichError: ErrorType {
    case NotMe
    case DoItYourself
}

然后我声明了一个抛出错误的方法(不是异常,伙计们。它是一个错误)。下面是这个方法:

func makeMeSandwich(names: [String: String]) throws -> String {
    guard let sandwich = names["sandwich"] else {
        throw SandwichError.NotMe
    }

    return sandwich
}

问题来自调用方。下面是调用此方法的代码:

let kitchen = ["sandwich": "ready", "breakfeast": "not ready"]

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
    print("Not me error")
} catch SandwichError.DoItYourself {
    print("do it error")
}

do行之后,编译器说Errors thrown from here are not handled because the enclosing catch is not exhaustive。但在我看来,它是详尽的,因为在SandwichError枚举中只有两种情况。
对于常规的switch语句,swift可以理解它在处理每种情况时都是详尽的。

34gzjxbg

34gzjxbg1#

Swift 2错误处理模型有两个要点:它们合在一起,可以归结为您的do/catch语句需要捕获每个可能的错误,而不仅仅是那些您知道会抛出的错误。
注意,我们没有声明函数会抛出什么类型的错误,只声明它是否会抛出错误,这是一个0 - 1-无穷大类的问题:作为一个定义函数供他人(包括未来的自己)使用的人,您不希望函数的每个客户端都必须适应函数实现中的每一个变化,包括它可能引发的错误。您希望调用函数的代码能够适应这种变化。
因为你的函数不能说明它抛出的错误类型(或者将来可能会抛出),捕获错误的catch块不知道它可能抛出什么类型的错误。您需要使用通用的catch语句来处理那些不需要的错误--这样,如果您的函数更改了它在将来抛出的错误集,调用方仍将捕获它的错误。

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
    print("Not me error")
} catch SandwichError.DoItYourself {
    print("do it error")
} catch let error {
    print(error.localizedDescription)
}

但是,我们不能就此止步,我们还要再思考一下这种弹性的概念。在设计三明治时,你必须描述每一个使用错误的地方。这意味着,每当你改变错误案例集时,你就必须改变每一个使用它们的地方......这可不是什么好玩的事。
定义您自己的错误类型的想法是让您集中处理类似的事情。您可以为您的错误定义一个description方法:

extension SandwichError: CustomStringConvertible {
    var description: String {
        switch self {
            case NotMe: return "Not me error"
            case DoItYourself: return "Try sudo"
        }
    }
}

然后,错误处理代码可以要求错误类型描述其自身--现在,处理错误的每个地方都可以使用相同的代码,并且还可以处理将来可能出现的错误情况。

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch let error as SandwichError {
    print(error.description)
} catch {
    print("i dunno")
}

这也为错误类型(或它们的扩展)支持其他报告错误的方式铺平了道路--例如,您可以在错误类型上有一个扩展,它知道如何向iOS用户提供一个UIAlertController来报告错误。

r1zk6ea1

r1zk6ea12#

我怀疑这只是还没有得到正确的实现。Swift编程指南似乎明确暗示编译器可以推断出穷举匹配'就像switch语句'。它没有提到需要一个通用的catch才能做到穷举。
您还将注意到,错误出现在try行,而不是块的末尾,也就是说,在某个点上,编译器将能够查明块中的哪个try语句具有未处理的异常类型。
虽然文档有点模糊,我浏览了一下“Swift的新功能”视频,没有找到任何线索;我会继续努力的

更新日期:

我们现在到了Beta 3,没有任何ErrorType推断的提示。我现在相信,如果这是曾经计划过的(我仍然认为在某个时候是计划过的),协议扩展上的动态调度可能会杀死它。

测试版4更新:

Xcode 7 b4增加了对Throws:的doc注解支持,这“应该用来记录可以抛出什么错误以及为什么”,我猜这至少提供了 * 一些 * 机制来将错误传达给API消费者,当你有文档的时候,谁还需要类型系统呢!

其他更新:

在花了一些时间希望自动ErrorType推理,并找出该模型的局限性后,我改变了主意--我希望苹果实现的是this。本质上:

// allow us to do this:
func myFunction() throws -> Int

// or this:
func myFunction() throws CustomError -> Int

// but not this:
func myFunction() throws CustomErrorOne, CustomErrorTwo -> Int

另一项更新

Apple的错误处理基本原理现在可以在here上找到。在swift-evolution邮件列表上也有一些有趣的讨论。本质上,John McCall反对类型化错误,因为他相信大多数库最终都会包含一个通用的错误情况。并且类型化的错误不太可能在代码中添加太多内容克里斯·拉特纳(Chris Lattner)说,如果Swift 3能与弹性模型一起工作,他愿意接受Swift 3中的输入错误。

k97glaaz

k97glaaz3#

Swift担心case语句没有覆盖所有case,要解决这个问题,需要创建一个默认case:

do {
    let sandwich = try makeMeSandwich(kitchen)
    print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
    print("Not me error")
} catch SandwichError.DoItYourself {
    print("do it error")
} catch Default {
    print("Another Error")
}
uplii1fm

uplii1fm4#

我也对缺少一个函数可以抛出的类型感到失望,但是我现在得到了它,这要感谢@rickster,我将这样总结它:假设我们可以指定一个函数抛出的类型,我们会得到如下结果:

enum MyError: ErrorType { case ErrorA, ErrorB }

func myFunctionThatThrows() throws MyError { ...throw .ErrorA...throw .ErrorB... }

do {
    try myFunctionThatThrows()
}
case .ErrorA { ... }
case .ErrorB { ... }

问题是,即使我们不更改myFunctionThathrows中的任何内容,如果我们只是向MyError添加一个错误用例:

enum MyError: ErrorType { case ErrorA, ErrorB, ErrorC }

我们就完蛋了,因为我们的do/try/catch不再是详尽无遗的,我们调用抛出MyError的函数的任何其他地方也是如此

u3r8eeie

u3r8eeie5#

enum NumberError: Error {
  case NegativeNumber(number: Int)
  case ZeroNumber
  case OddNumber(number: Int)
}

extension NumberError: CustomStringConvertible {
         var description: String {
         switch self {
             case .NegativeNumber(let number):
                 return "Negative number \(number) is Passed."
             case .OddNumber(let number):
                return "Odd number \(number) is Passed."
             case .ZeroNumber:
                return "Zero is Passed."
      }
   }
}

 func validateEvenNumber(_ number: Int) throws ->Int {
     if number == 0 {
        throw NumberError.ZeroNumber
     } else if number < 0 {
        throw NumberError.NegativeNumber(number: number)
     } else if number % 2 == 1 {
         throw NumberError.OddNumber(number: number)
     }
    return number
}

现在验证编号:

do {
     let number = try validateEvenNumber(0)
     print("Valid Even Number: \(number)")
  } catch let error as NumberError {
     print(error.description)
  }
x8goxv8g

x8goxv8g6#

可以使用catch中的switch case来处理错误

func  checkAge(age:Int) throws {

    guard !(age>0 && age < 18) else{
        throw Adult.child
    }

    guard !(age >= 60) else{
        throw Adult.old
    }

    guard (age>0) else{
        throw Adult.notExist
    }

}

   do{
       try checkAge(age:0)

    }
    catch let error {
        switch error{
        case Adult.child : print("child")
        case Adult.old : print("old")
        case Adult.notExist : print("not Exist")
        default:
            print("default")
        }
    }

enum Adult:Error {
    case child
    case old
    case notExist
}
mum43rcc

mum43rcc7#

创建如下枚举:

//Error Handling in swift
enum spendingError : Error{
case minus
case limit
}

创建方法如下:

func calculateSpending(morningSpending:Double,eveningSpending:Double) throws ->Double{
if morningSpending < 0 || eveningSpending < 0{
    throw spendingError.minus
}
if (morningSpending + eveningSpending) > 100{
    throw spendingError.limit
}
return morningSpending + eveningSpending
}

现在检查有无错误并处理:

do{
try calculateSpending(morningSpending: 60, eveningSpending: 50)
} catch spendingError.minus{
print("This is not possible...")
} catch spendingError.limit{
print("Limit reached...")
}

相关问题