- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在仔细阅读论坛和 Swift 文档后(我承认不完全),似乎在 Swift 中我们鼓励编写更安全的代码,而不是 try-catch 机制。鉴于此,我对示例 API 有疑问,并想了解如何更安全地处理这种情况:
例如,我可以使用 NSDecimalNumberHandler 创建以下类:
class MathWhiz {
init() {
let defaultBehavior: NSDecimalNumberHandler =
NSDecimalNumberHandler.defaultDecimalNumberHandler()
}
func add(op1: String, op2: String) ->NSDecimalNumber {
return NSDecimalNumber.decimalNumberWithString(op1).decimalNumberByAdding(NSDecimalNumber.decimalNumberWithString(op2))
}
}
如果我使用以下内容,我会得到一个数字:
let brain = MathWhiz()
brain.add("1", op2: "1e127")
但是,如果我导致溢出异常,:
brain.add("1", op2: "1e128")
我会按预期使程序崩溃。
所以,我的问题是,API 会引发异常,但我不会在这里处理它们。还有其他人指出 Swift 没有异常处理,但是这个问题正在寻找一种很好的方法来以语言创建者认为应该完成的方式来处理这个问题。有没有推荐的方法来处理这个问题,而不必编写我自己的代码来检查溢出、下溢、精度损失等……?我希望 NSDecimalNumberHandler 为我做这件事。
最佳答案
如果你在 Swift 中设计一个函数(或方法),你至少有 3 种处理错误的选择:
选择 1:返回可选类型
如果您的函数可能会失败,并且这种情况经常发生,请考虑返回一个可选类型变量。例如,在您的情况下,您的方法 add
可以返回 NSDecimalNumber?
而不是普通的 NSDecimalNumber
。在这种情况下,您的方法将检查所有可能出错的地方,并在这些情况下返回 nil
。上溢和下溢将返回 nil
,所有其他情况将返回 NSDecimalNumber
。调用者必须像这样检查并解包可选的 NSDecimalNumber:
let brain = MathWhiz()
if let sum = brain.add("1", op2: "1e127") {
println("the result was \(sum)")
} else
println("something went wrong with MathWhiz add")
}
选择 2:返回枚举类型
如果您想返回有关出错的更多信息,您可以创建一个枚举类型,每个错误都有一个值,成功也有一个值,其中嵌入了答案。例如,您可以这样做:
enum MathWhizResult {
case Overflow
case Underflow
case Success(NSDecimalNumber)
}
然后 add 将被定义为返回 MathWhizResult
:
func add(op1: String, op2: String) -> MathWhizResult
如果出现错误,add
将返回.Overflow
或.Underflow
。如果成功,add
将返回 Success(result)
。调用者必须检查枚举并解压结果。 switch
可用于此目的:
switch (brain.add("1", op2: "1e128")) {
case .Overflow
println("darn, it overflowed")
case .Underflow
println("underflow condition happened")
case .Success(let answer)
println("the result was \(answer)"
}
选择3:选择不显式处理错误
在前两个选项中解包结果对于一个非常罕见的错误来说可能开销太大。您可以选择只返回一个结果,让调用者处理下溢或溢出情况的可能性。在这种情况下,他们必须在调用 add
之前自行检查这些条件。好处是,如果他们知道他们的程序永远不会导致下溢或溢出(例如,因为他们处理的是个位数),他们就不会为解包结果而烦恼。
我创建了一个小应用程序来演示如何使用 NSDecimalNumbers
执行此操作。我在 Xcode
中创建了一个 Single View Application
。在 StoryBoard
的 ViewController
中,我添加了 3 个 TextField
(操作数 1、操作数 2 和结果各一个)和一个 按钮
,我标记为+
。
ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBOutlet var operand1 : UITextField!
@IBOutlet var operand2 : UITextField!
@IBOutlet var result : UITextField!
var brain = MathWhiz()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func addButton(sender : UIButton) {
var op1 = operand1.text
var op2 = operand2.text
// Perform the add with the contents of the operand fields.
// Print the answer, or "No Result" if add returns nil.
if let answer = brain.add(op1, op2: op2)?.description {
result.text = answer
} else {
result.text = "No Result"
}
}
}
MathWhiz.swift
import UIKit
// Declare that we implement NSDecimalNumberBehaviors so that we can handle
// exceptions without them being raised.
class MathWhiz: NSDecimalNumberBehaviors {
var badException = false
// Required function of NSDecimalNumberBehaviors protocol
func roundingMode() -> NSRoundingMode {
return .RoundPlain
}
// Required function of NSDecimalNumberBehaviors protocol
func scale() -> CShort {
return CShort(NSDecimalNoScale)
}
// Required function of NSDecimalNumberBehaviors protocol
// Here we process the exceptions
func exceptionDuringOperation(operation: Selector, error: NSCalculationError, leftOperand: NSDecimalNumber, rightOperand: NSDecimalNumber) -> NSDecimalNumber? {
var errorstr = ""
switch(error) {
case .NoError:
errorstr = "NoError"
case .LossOfPrecision:
errorstr = "LossOfPrecision"
case .Underflow:
errorstr = "Underflow"
badException = true
case .Overflow:
errorstr = "Overflow"
badException = true
case .DivideByZero:
errorstr = "DivideByZero"
badException = true
}
println("Exception called for operation \(operation) -> \(errorstr)")
return nil
}
// Add two numbers represented by the strings op1 and op2. Return nil
// if a bad exception occurs.
func add(op1: String, op2: String) -> NSDecimalNumber? {
let dn1 = NSDecimalNumber(string: op1)
let dn2 = NSDecimalNumber(string: op2)
// Init badException to false. It will be set to true if an
// overflow, underflow, or divide by zero exception occur.
badException = false
// Add the NSDecimalNumbers, passing ourselves as the implementor
// of the NSDecimalNumbersBehaviors protocol.
let dn3 = dn1.decimalNumberByAdding(dn2, withBehavior: self)
// Return nil if a bad exception happened, otherwise return the result
// of the add.
return badException ? nil : dn3
}
}
关于exception-handling - Swift Exceptions 异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24269395/
这个问题在这里已经有了答案: Python try...except comma vs 'as' in except (5 个回答) 关闭7年前。 在python中,有两种方法可以捕获异常 excep
在 Java 中,我有一个从 Exception 扩展的异常类,但是每当我抛出它时,编译器都会说它需要被捕获/必须声明方法 throws异常。 当我使用从 Exception 扩展的 RuntimeE
我有一组用户、组以及用户和组之间的映射。我有各种操作这些集合的函数,但是不能为不存在的用户添加用户组映射,也不能删除仍然有用户作为成员的组等。 所以基本上我希望这些函数抛出必须由调用者明确处理的“异常
我正在尝试使用上载控件上载20兆的文件,并且在Visual Studio的内置Web服务器上可以正常工作,但是一旦将其发布到生产服务器(我无权访问),我总是收到以下错误消息: Server Error
我想断言运行某些代码时会引发特定异常(SSLHandshakeException)。 assertThatThrownBy(() -> { // some code }).is
这个问题我暂时解决不了。我很乐意提供一些建议。 当我尝试抛出异常时(我自己创建了一个 Java 风格的异常) throw Exception (); 编译器提出抗议: DataTypes/Date.c
我有以下文件: from fabric.api import env, execute, run env.hosts = ['1.2.3.4'] def taskA(): run('ls')
我正在阅读一些包含类似于以下功能的源代码: def dummy_function(): try: g = 1/0 except Exception as e:
根据标准 ML 的定义(修订版): The idea is that dynamic evaluation of a non-expansive expression will neither gen
当 GHCi 在运行时发现调用产生的值与函数的模式匹配不匹配时,有没有办法让 GHCi 产生更好的异常消息? 它目前给出了产生非详尽模式匹配的函数的行号,虽然有时会有所帮助,但确实需要一轮调试,有时我
我有一个最佳实践问题。我意识到这是主观的,但想问问比我更聪明的人,这是否是一种常见的编程实践。 如果您有一种不希望干扰应用程序重要功能的非关键方法,那么使用这样的错误接收器是否常见? Try
在编程中,异常是否总是错误(被零除,访问冲突等等)? 如果不是,您能否提供不是错误的异常示例? 谢谢。 最佳答案 异常通常用于管理错误,它们使错误处理更加容易,但它们并不总是错误。 任何需要单独代码路
我很想知道 OCaml 运行时如何处理异常以使它们如此轻量。他们是使用 setjmp/longjmp 还是在每个函数中返回一个特殊值并传播它? 在我看来,longjmp会给系统带来一点压力,但只有在引
在我的 C# 代码中,我可以访问 MyNamespace.Exception 以及 System.Exception。当我想捕获其中一个异常时,理想情况下我会完全限定要捕获的异常或使用别名来明确说明。
我正在使用 Visual C++ 2005 Express Edition 并遇到以下链接器错误: 19>mylib1.lib(mylibsource1.obj) : error LNK2019: u
这个问题在这里已经有了答案: Is there "Break on Exception" in IntelliJ? (6 个回答) 关闭7年前。 我想在调试器中运行我的测试套件并中断任何意外异常,但是
Like in this picture 我知道它们都可以正常工作,但我只是想知道它们之间有何不同? PS:我是初学者。 最佳答案 A LogEvent可以同时包含消息和异常。如果您使用第一种形式:
我知道避免 Doctrine 上的异常似乎是一种奇怪的行为,但我需要这样做,因为我在一个旧项目中工作,过去有人执行了一些迁移,然后他决定删除它,所以现在复制起来很复杂本地生产环境没有崩溃,这就是为什么
我想创建一个名为 SecurityException 的新异常。 我应该把代码放在哪里? class SecurityException extends CakeException {}; 谢谢! 最
我一直在使用throw new Exception("...")在我的代码中,因为我找不到其他可以使用的东西。我正在寻找像 C++'s 这样的东西 out_of_range 和 logic_error
我是一名优秀的程序员,十分优秀!