为什么null检查不好?为什么我要一个可选的成功(如果它为null)?

时间:2018-10-30 03:22:43

标签: swift kotlin null optional

我已经阅读了多个类似问题的答案以及一些教程,但没有一个能解决我的主要困惑。我是本地Java程序员,但是我也已经在Swift中编程。

我为什么要使用可选参数而不是null?

我已经读过,这样可以减少空检查和错误,但是使用干净的编程是必须或容易避免的。

我也读过它,所以所有引用都成功了(https://softwareengineering.stackexchange.com/a/309137/227611val length = text?.length)。但是我认为这是一件坏事或不当用语。如果我调用length函数,我希望它包含一个长度。如果没有,则代码应在此处处理,而不要继续。

我想念什么?

3 个答案:

答案 0 :(得分:2)

可选选项使类型更清晰。一个Int始终存储实际值,而一个可选Int(即Int?)则存储Int或nil的值。可以说,这种显式的“双重”类型使您可以设计一个简单的函数,该函数可以明确声明它将接受并返回的内容。如果您的功能是简单地接受一个实际的Int并返回一个实际的Int,那就太好了。

func foo(x: Int) -> Int

但是,如果您的函数要允许返回值为nil,而参数为nil,则必须通过将其显式设置为可选值来实现:

func foo(x: Int?) -> Int?

在其他语言(例如Objective-C)中,对象始终可以为nil。 C ++中的指针也可以为零。因此,应该检查在Obj-C中收到的任何对象或在C ++中收到的任何指针是否为零,以防万一它不是您的代码所期望的(真实的对象或指针)。

在Swift中,关键是您可以声明非可选的对象类型,因此,无论您使用什么代码处理这些对象,都无需进行任何检查。他们可以安全地使用这些对象,并知道它们不是null。这是Swift可选控件功能的一部分。并且,如果您收到可选的内容,则在需要访问其值时必须明确将其解压缩为它的值。那些使用Swift进行编码的人会尽力使它们的功能和属性始终是非可选的,除非他们确实有理由使它们成为可选。

Swift可选对象的另一个美丽之处是所有内置的语言结构,用于处理可选对象,以使代码更快地编写,更清晰地阅读,更紧凑……省去了检查的麻烦并解压缩一个可选的选项,以及与其他语言等效的选项。

nil-coalescing运算符(??)就是一个很好的例子,if-let和guard以及许多其他运算符也是如此。

总而言之,可选参数鼓励并强制在代码中进行更明确的类型检查-类型检查由编译器而不是在运行时完成。当然,您可以用任何语言编写“干净的”代码,但是在Swift中这样做要简单得多,也更加自动化,这在很大程度上要归功于它的可选(也包括非可选!)。

答案 1 :(得分:0)

  1. 避免在编译时出错。这样您就不会无意间传递null。

  2. 在Java中,任何变量都可以为null。因此,在使用null之前先检查是否为空成为一种习惯。快速操作时,只有optional可以为null。因此,您只需要检查可选值是否为空值即可。

  3. 您不必总是检查可选项。您可以在不解开可选内容的情况下同样出色地工作。将方法发送到具有空值的optional不会破坏代码。

可能还有更多,但是那些有很大帮助。

答案 2 :(得分:0)

TL / DR:编译器还可以更严格的方式避免使用干净的编程可以避免的空检查。编译器可以以更严格的方式强制执行您所说的必要的空检查。可选的类型构造使之成为可能。


  

var length = text?.length

这实际上是可选方法有用的一种很好的例子。如果文本没有值,则长度也不能。在Objective-C中,如果text为nil,则您发送的任何消息均不执行任何操作并返回0。该事实有时很有用,并且可以跳过很多nil检查,但也可能导致细微的错误。

另一方面,许多其他语言指出了这样的事实,即您已在执行代码时立即崩溃,从而将消息发送到nil指针。这样可以更轻松地在开发过程中查明问题,但是运行时错误发生在用户身上的可能性并不大。

Swift采用另一种方法:如果text没有指向具有长度的内容,则没有长度。可选不是指针,它是一种具有值或没有值的类型。您可能会假设变量lengthInt,但实际上是Int?,它是完全不同的类型。

  

如果我调用length函数,我希望它包含一个长度。如果没有,则代码应在此处处理,而不要继续。

如果text为nil,则没有对象向length发送消息,因此length永远不会被调用,结果为nil。有时候很好-有道理的是,如果没有text,那么也就不会有length。您可能并不在意–如果您准备在text中绘制字符,那么没有length的事实将不会打扰您,因为无论如何都没有绘制内容。 textlength的可选状态迫使您处理以下事实:这些变量在需要值的位置没有值。

让我们看一个更具体的版本:

var text : String? = "foo"
var length : Int? = text?.count

这里,text有一个值,所以length也有一个值,但是length仍然是可选的,因此在将来的某个时候,您必须检查一下在使用前存在一个值。

var text : String? = nil
var length : Int? = text?.count

在上面的示例中,text为nil,因此length也为nil。同样,您必须处理以下事实:在尝试使用这些值之前,textlength可能都没有值。

var text : String? = "foo"
var length : Int = text.count

猜猜这里会发生什么?编译器会说 哦,不,你不要! ,因为text是可选的,这意味着从中获取的任何值也必须是可选的。但是代码将length指定为非可选Int。让编译器在编译时指出这个错误要比让用户在更晚的时候指出这个错误好得多。

var text : String? = "foo"
var length : Int = text!.count

在这里,!告诉编译器您认为自己知道自己在做什么。毕竟,您只是text分配了一个实际值,因此可以假设text不为零是非常安全的。您可能会这样编写代码,因为您希望考虑到text之后可能变为nil的事实。如果您不确定,请不要强行打开可选选项,因为...

var text : String? = nil
var length : Int = text!.count

...如果text 为零,则表明您背叛了编译器的信任,并应得到(和您的用户)得到的运行时错误:

error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

现在,如果text不是可选的,那么生活就很简单:

var text : String = "foo"
var length : Int = text.count

在这种情况下,您知道 textlength都可以安全使用,而无需进行任何检查,因为它们不可能为零。您不必小心“干净”-实际上,您不能将无效的String分配给text,并且每个String都有一个{{1 }},因此count将获得一个值。

  

我为什么要使用可选参数而不是null?

在Objective-C的早期,我们曾经手动管理内存。有一个small number of simple rules,如果您严格遵守规则,那么Objective-C的保留计数系统就可以很好地工作。但是,即使是我们最好的人也会偶尔溜走,有时会出现复杂的情况,在其中很难确切知道该怎么做。 StackOverflow和其他论坛上与内存管理规则有关的大部分Objective-C问题。然后苹果推出了ARC(自动保留计数),其中编译器接管了保留和释放对象的职责,并且内存管理变得更简单了。我现在打赌不到1%的Objective-C和Swift关于SO的问题现在与内存管理有关。

可选内容如下::它们将负责跟踪变量的责任从程序员转移到了编译器。 >