《深入理解Scala》——第2章,第2.4节用None不用null

简介:

本节书摘来自异步社区《深入理解Scala》一书中的第2章,第2.4节用None不用null,作者[美]Josh Suereth,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.4 用None不用null
深入理解Scala
Scala在标准库里提供了scala.Option类,鼓励大家在一般编程时尽量不要使用null。Option可以视作一个容器,里面要么有东西,要么什么都没有。Option通过两个子类来实现此含义:Some和None。Some表示容器里有且仅有一个东西,None表示空容器,有点类似List的Nil的含义。
在Java和其他允许null的语言里,null经常作为一个占位符用于返回值,表示非致命的错误,或者表示一个变量未被初始化。Scala里,你可以用Option的None子类来代表这个意思,反过来用Option的Some子类代表一个初始化了的变量或者非致命(non-fatal)的变量状态。我们来看看这两个类的用法。


6ffa3d4a55e4a132d47050aeb0c14d1fcb624e24

不包含任何值的Option用None对象来构建,包含一个值的Option用Some工厂方法来创建。Option提供了很多不同的方法用来把其值取出来。用得特别多的是get和getOrElse方法。get方法会尝试访问Option里保存的值,如果Option是空的则抛出异常。这和其他语言里访问可能为null的变量一样。getOrElse也访问Option里存放的值,有则返回,否则返回其参数(作为默认值)。你应该尽量使用getOrElse而不是get。
Scala在Option的伴生对象里提供了工厂方法,这个方法能把Java风格的引用(null代表空变量)转换为Option类型,使其更明确。我们快速过一下。

5e3770500be6010123274adf79044769d5504d4a

如果输入是null,Option工厂方法会创建一个None对象,如果输入是初始化了的值,则创建一个Some对象。这使我们处理来自不信任的来源(比如另一种JVM语言)的输入,把输入包装成Option时容易许多。你可能会问,为什么我要这么做?代码里检查一下null不是一样简单吗?好吧,Option提供了一些高级特性,使它比简单用if null检查要理想得多。
Option高级技巧
Option的最重要特性是可以被当作集合看待。这意味着你可以对Option使用标准的map、flatMap、foreach等方法,还可以用在for表达式里。这不仅有助于确保优美简洁的语法,而且开启了另一种不同的处理未初始化值的方法。我们来看几个常见问题,分别用null和Option来解决。第一个问题是创建对象或返回默认值。
1.创建对象或返回默认值
代码里有很多地方需要在某变量有值的时候构建某结果,变量没值的时候构建一个默认值。假设我们有个应用在执行时需要某种临时文件存储。应用设计为用户能在命令行下提供可选的参数指定一个目录来存放临时文件,如果不指定目录,那我们要返回一个合理的默认临时文件目录。我们来创建一个返回临时文件目录的方法。


0fe9063786c9c51fcdee69321081425c3ddcd858

getTemporaryDirectory接受Option[String]类型的参数,返回指向我们将使用的临时文件目录的File对象。我们首先对option应用map方法,在参数有值的情况下创建一个File对象。然后我们用filter方法来确保这个新创建的文件对象必须是目录,filter方法检查option里的值是否符合断言要求,如果不符合就转化为None。最后我们检查Option里是否有值,如果没有则返回默认的文件路径。
这使得我们可以不需要嵌套很多(判断是否为空的)if语句或代码块就可以实施一系列的检查。有时候我们会想要基于某个参数是否存在来决定是否执行一个代码块。
2.如果变量已初始化则执行代码块
可以通过foreach方法来做到仅当Option有值时才执行某段代码块。foreach方法正如其名所示,遍历Option里的所有值。因为Option只能有零或一个值,所以其代码块要么执行,要么不执行。foreach语法和for表达式协作尤其好用。我们来看个例子。


a4726b11f1d6015bd3bc186e5e8b98cb57ec828f

如你所见,代码看上去就像一般的“迭代一个集合”的控制块。如果我们需要迭代多个变量,还是用相似的语法。我们来看个案例,假设我们使用某种Java Servlet框架,现在我们想要对用户做验证。如果验证成功,我们要把安全令牌注入(inject)HttpSession,以便后续的filter和servlet可以检查用户的访问权限。


e1b0f9bd33487fb62bdce39aecc72c508452da9d

注意你可以在for表达式里嵌入条件逻辑。这样可以在代码里少用嵌套的逻辑代码块。另一个要点是所有的辅助方法都不需要使用Option类。Option用作对未初始化变量的一道优良的防火墙,你代码的其他部分可以不受污染(译者注:指不需要到处判断非空,也不需要到处使用Option,防火墙后的部分直接处理有值的情况就可以了)。在Scala里,参数类型为Option表示参数可能是未初始化的。Scala的惯例是不要把null或未初始化的参数传给函数。
Scala的for表达式相当强大,你甚至可以用它产生值,而不只是执行代码块。当你想把一些可能为空的参数转化为某个其他结果变量的时候,这个功能就非常好用了。
3.用多个可能未初始化的变量构造另一个变量
有时候我们需要把多个可能未初始化的变量转化为一个变量以便处理。为此我们要再次使用for表达式,这次加上yield。我们来看个案例,假设我们从用户输入或者某个安全位置读取了数据库配置信息,然后尝试用这个参数创建数据库连接。因为这只是个工具函数,不需要直接面对用户,所以我们不想对获取连接失败的情况做很多处理。我们只想简单地把数据库配置参数转化为一个Option,里面放上我们的数据库连接。


15fc1a17d5f773820821f22dbd7365ae0f32fdfe

这个函数准确地达成了我们期望,虽然看上去只是在DriverManager.getConnection外面包了一层。那如果我们想把这种包装方法抽象化,让我们能把任意函数包装成同样对Option友好的版本要怎么做呢?来看一下我们称为lift的函数。


87f9084e7ea0249c81b0e78db9564f7d978c9522

lift3方法看上去有点像我们之前那个createConnection方法,差别在于它接受一个函数作为唯一的参数。如你在REPL里所见,我们可以把它应用在已有的函数上,创建出Option友好的函数来。我们直接接受DriverManager.getConnection方法,然后把它提升(lift)为语义上与我们之前的createConnection方法相等的函数。这个技巧在“封装”未初始化变量时很有效。你在写大部分代码,包括工具类时,可以假定所有变量都是初始化好的,然后在需要的地方把你的函数lift成Option友好的版本。
有一点要重点注意,Option根据其包含的值来计算判等和散列值。用Scala的时候,理解判等和散列值是非常重要的,尤其是在多态的场景下。

相关文章
|
11月前
|
机器学习/深度学习 SQL 关系型数据库
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
116 0
|
11月前
|
SQL 关系型数据库 MySQL
总结 vue3 的一些知识点:MySQL NULL 值处理
总结 vue3 的一些知识点:MySQL NULL 值处理
|
11月前
|
SQL 关系型数据库 MySQL
MySQL NULL 值处理
MySQL NULL 值处理
|
11月前
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用合集之从MySQL同步数据到Doris时,历史数据时间字段显示为null,而增量数据部分的时间类型字段正常显示的原因是什么
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
11月前
|
SQL 关系型数据库 MySQL
python在mysql中插入或者更新null空值
这段代码是Python操作MySQL数据库的示例。它执行SQL查询从表`a_kuakao_school`中选取`id`,`university_id`和`grade`,当`university_id`大于0时按升序排列。然后遍历结果,根据`row[4]`的值决定`grade`是否为`NULL`。若不为空,`grade`被格式化为字符串;否则,设为`NULL`。接着构造UPDATE语句更新`university`表中对应`id`的`grade`值,并提交事务。重要的是,字符串`NULL`不应加引号,否则更新会失败。
228 2
|
8月前
|
SQL 关系型数据库 MySQL
在 MySQL 中使用 IS NULL
【8月更文挑战第12天】
787 0
在 MySQL 中使用 IS NULL
|
8月前
|
SQL 关系型数据库 MySQL
mysql不等于<>取特定值反向条件的时候字段有null值或空值读取不到数据
对于数据库开发的专业人士来说,理解NULL的特性并知道如何正确地在查询中处理它们是非常重要的。以上所介绍的技巧和实例可以帮助你更精准地执行数据库查询,并确保数据的完整性和准确性。在编写代码和设计数据库结构时,牢记这些细节将有助于你避免许多常见的错误,提高数据库应用的质量与性能。
242 0
|
9月前
|
SQL 存储 索引
MySQL设计规约问题之为什么应该把字段定义为NOT NULL并且提供默认值
MySQL设计规约问题之为什么应该把字段定义为NOT NULL并且提供默认值
|
10月前
|
SQL 关系型数据库 MySQL
MySQL外键约束行为解析:CASCADE, NO ACTION, RESTRICT, SET NULL
MySQL外键约束行为解析:CASCADE, NO ACTION, RESTRICT, SET NULL
1096 0
|
10月前
|
关系型数据库 MySQL
MySQL中如何处理NULL值以及如何使用正则表达式
MySQL中如何处理NULL值以及如何使用正则表达式