Swift的错误处理是该语言的独特功能它看起来很像其他语言中的异常,但语法不完全相同,它也不尽如人意今天我要看看Swift错误在内部工作,今天小编就来说说关于swift问题分析?下面更多详细答案一起来看看吧!

swift问题分析(Swift的错误处理)

swift问题分析

Swift的错误处理是该语言的独特功能。它看起来很像其他语言中的异常,但语法不完全相同,它也不尽如人意。今天我要看看Swift错误在内部工作。

语义

我们先来看一下Swift错误如何在语言层面上工作。

任何Swift函数都可以使用throws关键字进行装饰,这表明它可以引发错误:

func getStringMightFail()throws - > String {...

要从这样的一个函数中抛出错误,请使用符合Error协议的值的throw关键字:

抛出MyError.brainNotFound

调用throws函数时,必须包含try关键字:

let string = try getStringMightFail()

try关键字不执行任何操作,但它是一个必需的标记,表示该函数可能会引发错误。调用必须在允许抛出错误的上下文中,无论是在throws函数中还是在带有catch处理程序的do块中。

要写一个catch处理程序,将try调用放在一个do块中,并添加一个catch块:

做{

let string = try getStringMightFail()

...

} catch {

prInt(“发生错误:\(错误)”)

}

当抛出错误时,执行跳转到catch块。抛出的值可用错误。您可以通过类型检查和条件以及多个catch子句来获得想法,但这些都是基础知识。有关所有详细信息的详细信息,请参阅Swift编程语言的错误处理部分。

这就是它的作用。它是如何工作的?

履行

为了找出它是如何工作的,我写了一些虚拟代码与错误处理我可以反汇编:

struct MyError:Error {

var x:Int

var y:Int

var z:Int

}

func投掷者(x:Int,y:Int,z:Int)throws - > Int {

抛出MyError(x:x,y:y,z:z)

}

func捕手(f:(Int,Int,Int)throws - > Int){

做{

让x =尝试f(1,2,3)

print(“Received \(x)”)

} catch {

print(“Caught \(error)”)

}

}

当然,现在Swift是开源的,我可以直接看看编译器的代码,看看它的作用。但这不是乐趣,而且这更容易。

事实证明,Swift 3和Swift 4做的不一样。我将简要介绍一下Swift 3,然后再来看看Swift 4,因为这是即将到来的。

Swift 3的工作原理是自动化Objective-C的NSError约定。编译器插入一个额外的隐藏参数,这个参数基本上是Error *或NSError **。抛出错误包括将错误对象写入该参数中传递的指针。调用者分配一些堆栈空间并在该参数中传递其地址。返回时,它会检查该空间是否现在包含错误。如果是,它跳到catch块。

斯威夫特4获得了一个好心人。基本思想是一样的,但是除了正常的额外参数之外,还会为错误返回保留一个特殊的寄存器。以下是Thrower中的相关汇编代码:

调用imp___stubs__swift_allocError

mov qword [rdx],rbx

mov qword [rdx 8],r15

mov qword [rdx 0x10],r14

mov r12,rax

这将调用Swift运行时分配一个新的错误,用相关的值填充它,然后把指针放在r12中。然后它返回给呼叫者。 Catcher中的相关代码如下所示:

叫r14

mov r15,rax

测试r12,r12

je loc_100002cec

它进行呼叫,然后检查r12是否包含任何内容。如果是,它跳到catch块。 ARM64上的技术几乎相同,x21寄存器用作错误指针。

在内部,它看起来很像返回Result类型,或者返回某种错误代码。 throws函数在特殊的地方将调用者的抛出错误返回给调用者。调用者检查该位置是否存在错误,如果是,则跳转到错误处理代码。生成的代码看起来类似于使用NSError **参数的Objective-C代码,实际上Swift 3的版本是相同的。

与异常比较

在讨论其错误处理系统时,Swift非常谨慎,不要使用“异常”这个词,但它看起来很像其他语言的例外。它的实现如何比较?有很多语言有例外,其中许多语言做的不同,但自然的比较是C 。 Objective-C异常(尽管它们确实存在,尽管没人使用它们)在现代运行时使用C 的异常机制。

充分探索C 异常如何工作可以填写一本书,所以我们必须解决一个简短的描述。

调用throw函数(这是C 函数的默认值)的C 代码正好像调用非抛出函数一样生成程序集。也就是说,它传递参数并检索返回值,没有考虑例外的可能性。这怎么可能工作?除了生成无异常代码之外,编译器还生成一个表,其中包含有关代码如何(以及是否)处理异常的信息,以及如何在抛出异常的情况下如何安全地展开堆栈以退出函数。当某些功能引发异常时,它会爬起堆栈,查找每个函数的信息,并使用它来将堆栈解压缩到下一个函数,直到找到异常处理程序或运行结束。如果它找到一个异常处理程序,它将控制权转移到该处理程序,然后在catch块中运行代码。有关C 异常如何工作的更多信息,请参阅C ABI for Itanium:异常处理。该系统被称为“零成本”异常处理。术语“零成本”是指当没有抛出异常时会发生什么。因为该代码的编译完全与没有例外一样,因此不支持异常的运行时开销。调用潜在投掷函数与调用不抛出函数一样快,并且将try块添加到代码中并不会在运行时完成任何额外的工作。当抛出异常时,“零成本”的概念出现在窗口之外。使用表解开堆栈是一个昂贵的过程,需要大量的时间。该系统围绕着很少抛出异常的想法进行设计,并且在没有抛出异常的情况下的性能更重要。这个假设在几乎所有的代码中都可能是真实的。相比之下,Swift的系统非常简单。它不会为throws和non-throws函数生成相同的代码。相反,每次调用throws函数后都要检查是否返回错误,如果是这样,则跳转到相应的错误处理代码。这些检查不是免费的,虽然它们应该很便宜。对于Swift来说,权衡是非常有意义的。 Swift错误看起来很像C 异常,但实际上它们的用法不一样。几乎任何C 调用都可能会抛出,甚至像新操作符这样的基本的东西也会被抛出来,以指示一个错误。在每次调用之后,明确地检查抛出的异常将添加大量额外的检查。相比之下,几个Swift电话在典型的代码库中被标记为throws,因此显式检查的成本很低。结论Swift的错误处理请求与其他语言(例如C )中的异常进行比较。 C 的异常处理在内部非常复杂,但Swift采取不同的方法。 Swift在常见的情况下,不用放松表来实现“零成本”,而是在特殊寄存器中返回抛出的错误,而调用者检查该寄存器以查看是否已经抛出错误。当错误不被抛出时,这增加了一些开销,但是避免了使C 做的事情变得非常复杂。编写Swift代码将会非常努力,错误处理的开销会产生明显的差异。

,