可选参数的全部原因是为了防止运行时因命中分配给nil / null /
none的变量而导致崩溃。因此,变量不能为零。而是可以将它们包装为Optional类型,将它们表示为Some或None,并展开以获取Some或nil的特定内容。
但是,如果您使用!
或Implicitly Unwrapped Optionals
到处都将它们解包,那么由于您是一个不完善的编码器,您只会引入运行时崩溃的可能性。如果您使用if let
它们来安全地展开包装,可以避免崩溃,但是您会陷入if let
语句范围内,无法使用Some中的值,并且仍然必须处理潜在的nil情况。如果使用?为了临时解包以调用方法,完成后将被重新包装,从而引入了多层可选包装的混乱可能性。
所以:在我看来,要做的是避免使用可选参数,除非必要时(例如,调用返回它们的框架方法时)。但是,如果我不使用可选参数,则意味着我的对象引用必须为非零,并且我无法弄清楚如何处理由于某种原因而不应该存在或不存在的情况,是分配给对象引用的值。
我的问题是:如何避免不需要零?似乎需要不同的编程方法。(或者我应该只使用可选参数,如果这就是我正在做的事情,那比像其他语言一样简单地对对象引用进行空html" target="_blank">赋值有什么好处呢?)
我知道这可能是一个主观的问题,但是我还应该问什么呢?我并不想引发争论,我真的想知道在编写更多Swift代码时正确的方法是什么。
没错,可选选项可能会很痛苦,因此您不应该过度使用它们。但是,它们不仅仅是使用框架时必须处理的事情。它们是对一个非常常见的问题的解决方案:如何处理一个调用,该调用返回的结果可能是正确的,也可能不是。
例如,以Array.first
成员身份。这是一个方便的实用程序,可为您提供数组的第一个元素。a.first
当您可以打电话时,为什么能够打电话是有用的a[0]
?因为在运行时数组可能为空,所以在这种情况下a[0]
会爆炸。您当然可以a.count
事先检查-
但随后可以再次检查
一个。你可能会忘记,
和
b。导致代码非常难看。
Array.first
通过返回一个可选值来解决这个问题。因此,在使用作为数组第一个元素的值之前,您必须先打开可选的包装。
现在,您的问题涉及仅在带有的块内存在的展开值if let
。想象一下并行代码,检查数组计数。会一样吧?
if a.count > 0 {
// use a[0]
}
// outside the block, no guarantee
// a[0] is valid
if let firstElement = a.first {
// use firstElement
}
// outside the block, you _can't_
// use firstElement
当然,如果计数为零,则可以执行从函数中尽早返回的操作。这行得通,但是有点容易出错–如果您忘记这样做,或者将其放在没有运行的条件语句中怎么办?本质上,您可以执行以下操作array.first
:在函数中先检查计数,然后再执行do
array.first!
。但这!
就像向您发出的信号–当心,您正在做一些危险的事情,如果您的代码不完全正确,您将感到遗憾。
可选选项还有助于使其他选项更美观。假设您要在数组为空的情况下默认该值。代替这个:
array.count > 0 ? a[0] : somedefault
你可以这样写:
array.first ?? somedefault
这在几种方面都更好。它把重要的事情放在首位:所需的值是表达式的开始方式,后跟默认值。与三元表达式不同,三元表达式首先使用检查表达式,然后是您实际想要的值,然后是默认值。它还更加万无一失-
避免打错更容易,而且使该错别字不会导致运行时爆炸。
再举一个例子:find
函数。这将检查值是否在集合中,并返回其位置的索引。但是该值可能不存在于集合中。其他语言可能会通过返回结束索引(不是指向值,而是指向最后一个值)来处理此问题。这就是所谓的“前哨”值-一个看起来像常规结果但实际上具有特殊含义的值。像前面的示例一样,在使用它之前,您必须检查结果是否等于结束索引。但是您必须
知道 要执行此操作。您必须查找文档find
并确认其工作方式。
find
当您了解可选用语时,通过返回可选内容是很自然的事情,因为这样做很明显是因为结果可能无效。上面提到的关于安全性的所有事情同样适用-
您不能无意间忘记并将结果用作索引,因为您必须先将其拆开。
也就是说,您可以过度使用可选选项,因为它们是必须检查的负担。这就是为什么数组下标不返回可选值的原因-
它将导致必须不断检查和解开它们的麻烦,尤其是当您知道所使用的索引有效的事实时(例如,您在人们将经常使用的for循环(在数组的有效索引范围内),!
从而使代码混乱而无益。但是随后添加了诸如first和last这样的辅助方法,以覆盖人们确实希望快速执行操作而不必先检查数组大小但又想安全地进行操作的常见情况。
(另一方面,预计迅速会通过无效的下标来定期访问“快速字典”,这就是为什么它们的[key]
方法确实返回可选的原因)
如果可以完全避免发生故障的可能性,那就更好了。例如,当不filter
匹配任何元素时,它不返回nil
可选值。它返回一个空数组。您可能会说:“显然会。”
但是,您会惊讶地发现,当某人实际上应该只返回一个空值时,他们经常使返回值像数组一样可选。因此,您完全应该说应该避免使用可选选项(除非必要时除外),这是完全正确的,这仅是必需含义的问题。在上面的示例中,我会说它们是必要的,并且是替代方案的更好解决方案。
下面的方法位于类中,后台线程每60秒调用一次。它将ping一个套接字,检查它是否处于活动状态,并将所有内容放在映射中。 另外,我在同一个类中有以下方法。方法将由多个读取线程(假设最多10个线程)同时调用,以获取下一个活动的套接字。 如果计时器线程在方法中的上工作,那么所有这10个线程都应该在其他活动套接字上工作(这10个线程中的每一个都在不同的活动套接字上工作) 和所有这10个线程应该始终在不同的
考虑下面的代码: 对于上面的代码,输出是:
问题内容: 我们都知道您由于以下原因而无法执行以下操作: 但这显然有时有效,但并非总是如此。这是一些特定的代码: 当然,这导致: 即使没有多个线程。无论如何。 解决此问题的最佳方法是什么?如何在不引发此异常的情况下循环地从集合中删除项目? 我还在这里使用任意值,不一定是an t,因此您不能依赖。 问题答案: 是安全的,您可以这样使用它: 注意,这是在迭代过程中修改集合的唯一安全方法。如果在进行迭代
我们有一个方法,其中我们收到一个
问题内容: 堆垛机。我一直在网站上搜索我的问题,但没有找到我想要的东西。我坚持下面的代码: 得到了一个不错的数组列表,但是如果我在ArrayList中添加更多“ newUsers”,它们似乎会相互覆盖。我不想创建一个newUser1,newUser2对象,因为稍后在我的程序中,我必须能够直接从该程序添加新用户。 如何实现呢? ValidateUser: } 问题答案: 如果我理解正确,那么您是以这
在上图实例中,可以通过ShowroomItem的引用或interface Vehicle的引用来引用myCar。相应地,客户端驱动程序/销售工程师将获得功能访问权。 我同意在实现阶段(例如Java),这里不需要类型标识,我们将把myCar当作自己使用的基类型(任一接口)的实例。 但在顺序图中(为了清楚起见),我无法指出myCar的驾驶员引用应该是Vehicle的,而SalesEngineer的引用