迅速。 功能可选。 第1部分

Optional是Swift中的基本类型。 尽管几乎无处不在,但大多数开发人员并未充分利用它,甚至没有以错误的方式使用它。 可选绑定反对DRY原理,并引入了不必要的条件。

在这个由多部分组成的系列文章中,我们将讨论Optional真正含义,如何正确使用它并应用一些高级知识,以便为Optional计算创建方便的功能性eDSL。

其他重要主题包括Swift中的依赖项注入策略,错误处理,隐式展开的Optionals和类型强制转换。 虽然不能总是避免使用最后两个,尤其是在与Objective-C代码交互时,但它们都是纯Swift的代码味道。

由于本系列的主要目的是理解功能概念以及如何在Swift中应用它们 ,因此我们将讨论和绘制而不是代码。

您会看到,还有很多工作要做。 第一部分从Optional 。 然后我们将讨论可选绑定 。 我们的旅程将把我们引向基本的功能概念: 纯功能 。 在那里,我们将停下来,探索更多内容,直到下一部分。

为什么可选?

在Objective-C中没有“ Optional这样的类型。 相反,如果函数或属性不返回值,则返回nil 空的 NSObject指针。 可以安全地将消息发送到nil并将其作为参数传递。

但是Swift没有像Objective-C这样的指针。 此外,如果任何类型可以为nil ,我们的程序如何保证类型安全? 如果我们传递nil字符串而不是数字,编译器如何弄清楚怎么办? 如果我们将nil传递给无法处理的函数怎么办? 为了处理此问题,引入了Optional

有什么可选的?

让我们看一下Optional声明:

 枚举可选 { 
  ///没有值 
 无案 
  ///值的存在 
 案例一些(包装) 
  ... 
  } 

因此,我们看到的第一件事告诉我们Optional容器类型 :它封装了一个值。

图片 1.简单显示一个可选的Int值容器。 这里的黄色圆圈表示普通类型,而蓝色正方形表示“可选”容器。

您会看到, .none没有任何类型约束,因此使用诸如nil这样的文字很方便。 一个空盒子只是一个盒子,没有什么有趣的。

Optional还可以保护您避免将nil值传递给无法处理它们的函数。 这就是可选绑定起作用的地方。

可选绑定

可选绑定是用于访问包装到Optional的值的语句。 它看起来比声音更好,并且具有熟悉的语法。 如果您已经尝试过一些Swift,您将不会感到害怕

 如果让地址= person.address { 
  ... 
}

有另一种构造,Swift开发人员也熟悉

 守卫let address = person.address else {return nil} 

事不宜迟,让我们深入现实生活。

现实生活中的例子

如您从Array情节中所知,我有许多了不起的同事。 在这一集中,我们再次见到他们。 因此,这是另一个代码回顾中的简单QR代码图像生成功能:

非常清晰而优雅的解决方案,不是吗? 就Swift的语法而言,此函数没有错。 在这里, 可选绑定开始游戏。 让我们绘制此函数的流程。 第一行看起来像

图片 2.最简单的可选绑定语句。

您可能会注意到极其熟悉的行为? 可选绑定看起来像一个条件语句 。 而且你是绝对正确的! 可选绑定是一个条件语句 。 目前,我们将进一步发展。

图3。 generate(from:size :)函数的图形表示。

这里发生了很多事情。 但是首先,让我们了解可选绑定的作用。 它迫使我们解开 Optional并处理nil案例。 这可以通过条件语句来实现。 实际上,如果我们只想对包装在Optional的值应用函数 ,为什么需要条件语句? 原因很简单:这种语法构造清晰易用。

图3。 还可以让我们看到如何将generate(from:size:)解耦。 有两种计算方法:从字符串生成图像,然后将图像转换为所需的格式。 它们使我们可以引入纯函数

没有太多功能

我们执行的第一个操作是从CIFilter获得CIImage

这是不纯函数的示例。 它的作用是 更改输入参数的状态并返回一个值。 坦白说,我们对此还无能为力。 您可以在Pic中观察到突变 3 ,其中setValue应用程序将CIFilter并更改了其形状。 如果我们将此filter变量传递给下一个函数,则该函数的结果可能会更改。 这就是功能codeImage(from:filter:)不纯的原因。

另一方面,将CIImage转换为给定大小的UIImage的第二个函数是纯函数

一般来说, image(from:scaledTo:)并非完全纯正。 原因是transform 变量 。 通过引入变量,我们声明了一个状态。 任何可变的数据,状态,内存管理等都是副作用

我们可以避免使用此transform变量,但是image(from:scaledTo:)的第三行看起来很难看而且很难看。

但是,由于Swift不是纯函数式语言 ,因此image(from:scaledTo:)在Swift中是纯函数 。 如果我们多次传递相同的CIImageCGSize值,则输出UIImage将始终相同,并且image(from:scaledTo:)之后, CIImageCGSize都不会更改。

为什么纯函数很重要?

纯函数介绍了我们可以从函数概念中借鉴的主要思想。 一切都与模块化有关。 纯功能与它们的环境松散耦合,因此很容易将它们组合成可重用的模块。 而且,纯功能易于测试,因为它们不需要环境配置。

如果纯函数使生活如此美好,那为什么我们都不使用纯函数语言呢? 答案在于表面:现实生活中充满了副作用。

这些副作用之一是缺少值 。 计算可能会返回一个,也可能不会返回。 计算不返回任何值是可以的这不是错误 -这是预期的行为。

有一种方法可以将不纯函数视为纯函数。 由于该主题非常复杂,因此我们将在以下几集中进行探讨。 但是可选绑定给了我们一个提示。

嵌套条件

因此,现在我们将原始功能拆分为较小的逻辑部分。 将它们组合在一起, generate(from:size:)转换为:

我们在一个条件语句中有多个可选计算,这很酷吗? 但是,这是怎么发生的呢? 我们可以在没有条件的情况下做同样的事情吗? 答案是肯定的。 这就是我们在第二部分中要做的。

现在,我想指出一个有趣的时刻。 虽然codeImage(from:filter:)image(from:scaledTo:)执行可选计算,但它们都不采用Optional参数。 另一方面,它们返回一个Optional值,这对我们的下一次旅行很有帮助。

摘要

在第一天,我们发现Optional是一个容器类型 ,它封装了一个值。 这样做是为了处理可能会或可能不会返回值的计算。 Optional背后的主要思想是, 缺少值是可以的,不应将其视为错误 。 看起来OptionalArray有很多共同之处,不是吗?

可选绑定不过是条件语句。 它迫使我们解开Optionals并处理我们甚至不想处理的空盒子。

探索纯函数时,我们了解了它们的主要目的:增加程序的模块化 。 尽管现实生活中的计算几乎总是不纯净的,但是在某些功能语言中,有一种方法可以将它们视为纯净的。

下一步是什么?

在下一部分中,我们将使用容器类型的好处。 为了使用类型推断,我们将介绍管道函数的应用程序和一些基本的函数技术,例如currying。

剧透警告: Swift不是一种功能语言。 Foundation或UIKit都不被设计为功能工具箱。 有了所有这些UI和联网功能,我们拥有许多州。 我不是在谈论内存管理。 因此,引入了所有花哨的(在Swift中)像currying这样的技术,只是为了展示概念想法

感谢您的阅读,下次再见😉

Interesting Posts