15-Scala使用Option、Some、None,避免使用null

2023-11-02

1.避免null使用

  大多数语言都有一个特殊的关键字或者对象来表示一个对象引用的是“无”,在Java,它是null。在Java 里,null 是一个关键字,不是一个对象,所以对它调用任何方法都是非法的。但是这对语言设计者来说是一件令人疑惑的选择。为什么要在程序员希望返回一个对象的时候返回一个关键字呢?

1. Scala的Option类型

 为了让所有东西都是对象的目标更加一致,也为了遵循函数式编程的习惯,Scala鼓励你在变量和函数返回值可能不会引用任何值的时候使用Option类型在没有值的时候,使用None,这是Option的一个子类。如果有值可以引用,就使用Some来包含这个值。Some也是Option的子类

  None被声明为一个对象,而不是一个类,因为我们只需要它的一个实例。这样,它多少有点像null关键字,但它却是一个实实在在的,有方法的对象。

  Scala Option(选项)类型用来表示一个值是可选的(有值或无值)。
Option[T] 是一个类型为 T 的可选值的容器: 如果值存在, Option[T] 就是一个 Some[T] ,如果不存在, Option[T] 就是对象 None 。

应用例子

Option类型的值通常作为Scala集合类型(List,Map等)操作的返回类型。比如Map的get方法:

scala> val capitals = Map("France"->"Paris", "Japan"->"Tokyo", "China"->"Beijing")
capitals: scala.collection.immutable.Map[String,String] = Map(France -> Paris, Japan -> Tokyo, China -> Beijing)

scala> capitals get "France"
res0: Option[String] = Some(Paris)

scala> capitals get "North Pole"
res1: Option[String] = None

Option有两个子类别,Some和None。当程序回传Some的时候,代表这个函式成功地给了你一个String,而你可以透过get()函数拿到那个String,如果程序返回的是None,则代表没有字符串可以给你。
在返回None,也就是没有String给你的时候,如果你还硬要调用get()来取得 String 的话,Scala一样是会抛出一个NoSuchElementException异常给你的。
我们也可以选用另外一个方法,getOrElse。这个方法在这个Option是Some的实例时返回对应的值,而在是None的实例时返回传入的参数。换句话说,传入getOrElse的参数实际上是默认返回值。

scala> capitals get "North Pole" get
warning: there was one feature warning; re-run with -feature for details
java.util.NoSuchElementException: None.get
  at scala.None$.get(Option.scala:347)
  at scala.None$.get(Option.scala:345)
  ... 33 elided

scala> capitals get "France" get
warning: there was one feature warning; re-run with -feature for details
res3: String = Paris

scala> (capitals get "North Pole") getOrElse "Oops"
res7: String = Oops

scala> capitals get "France" getOrElse "Oops"
res8: String = Paris

通过模式匹配分离可选值,如果匹配的值是Some的话,将Some里的值抽出赋给x变量:

def showCapital(x: Option[String]) = x match {
    case Some(s) => s
    case None => "?"
}

提示

Scala程序使用Option非常频繁,在Java中使用null来表示空值,代码中很多地方都要添加null关键字检测,不然很容易出现NullPointException。因此Java程序需要关心那些变量可能是null,而这些变量出现null的可能性很低,但一但出现,很难查出为什么出现NullPointerException。
Scala的Option类型可以避免这种情况,因此Scala应用推荐使用Option类型来代表一些可选值。使用Option类型,读者一眼就可以看出这种类型的值可能为None。

实际上,多亏Scala的静态类型,你并不能错误地尝试在一个可能为null的值上调用方法。虽然在Java中这是个很容易犯的错误,它在Scala却通不过编译,这是因为Java中没有检查变量是否为null的编程作为变成Scala中的类型错误(不能将Option[String]当做String来使用)。所以,Option的使用极强地鼓励了更加弹性的编程习惯。

详解Option[T]

在Scala里Option[T]实际上是一个容器,就像数组或是List一样,你可以把他看成是一个可能有零到一个元素的List。
当你的Option里面有东西的时候,这个List的长度是1(也就是 Some),而当你的Option里没有东西的时候,它的长度是0(也就是 None)。

for循环

如果我们把Option当成一般的List来用,并且用一个for循环来走访这个Option的时候,如果Option是None,那这个for循环里的程序代码自然不会执行,于是我们就达到了「不用检查Option是否为None这件事。

scala> val map1 = Map("key1" -> "value1")
map1: scala.collection.immutable.Map[String,String] = Map(key1 -> value1)

scala> val value1 = map1.get("key1")
value1: Option[String] = Some(value1)

scala> val value2 = map1.get("key2")
value2: Option[String] = None

scala> def printContentLength(x: Option[String]) {
     |   for (c <- x){
     |     println(c.length)
     |   }
     | }
printContentLength: (x: Option[String])Unit

scala> printContentLength(value1)
6

scala> printContentLength(value2)

map操作

在函数式编程中有一个核心的概念之一是转换,所以大部份支持函数式编程语言,都支持一种叫map()的动作,这个动作是可以帮你把某个容器的内容,套上一些动作之后,变成另一个新的容器。
现在我们考虑如何用Option的map方法实现length: xxx的输出形式:

先算出 Option 容器内字符串的长度
然后在长度前面加上 "length: " 字样
最后把容器走访一次,印出容器内的东西
scala> value1.map(_.length).map("length: " + _).foreach(println)
length: 6

scala> value1.map("length: " + _.length).foreach(println)
length: 6

透过这样「转换」的方法,我们一样可以达成想要的效果,而且同样不用去做「是否为 None」的判断。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

15-Scala使用Option、Some、None,避免使用null 的相关文章

  • 无法从 JAR 文件加载主类

    我有一个 Spark scala 应用程序 我尝试显示一条简单的消息 Hello my App 当我编译它时sbt compile并运行它sbt run没关系 我成功显示了我的消息 但他显示了错误 像这样 Hello my applicat
  • 在 Scala 中使用 Some() 和 Option()

    我一直在与 Scala 中解析 JSON 字符串的函数式方法的概念作斗争 并且在返回 Option something 的情况下碰壁了 我提出了这个问题 https stackoverflow com questions 9289647 a
  • 无法设置“sbt start”的内存设置

    我正在尝试奔跑sbt start在用 Scala 编写的 Play Framework 应用程序中 在一台机器上ec2 t2 microAWS 上的实例 但我不能因为内存不足 Java 运行时环境无法继续运行 该机器有 1GB 内存 但实际
  • 如何将 Jar 库添加到 IntelliJ Idea SBT Scala 项目?

    我创建了一个 IntelliJ Idea SBT Scala 项目 例如海科 西伯格的文章 http heikoseeberger blogspot com 2010 08 how to setup scala project with s
  • 隐式参数解析——设置优先级

    我正在尝试创建一个类型类Default为给定类型提供默认值 这是我到目前为止所想到的 trait Default A def value A object Default def withValue A a A new Default A
  • Scala 在调用单参数函数时为什么以及如何特殊对待元组?

    scala 将多个函数调用参数合并到一个元组中 这可以禁用吗 https stackoverflow com questions 2850902讨论 Scala 创建一个元组来绑定到一个 arg 函数 这导致 scala gt printl
  • 如何在 Simple Build Tool 项目中调用 scala 解释器?

    我的 scala 程序正在使用 scala tools nsc interpreter IMain 的编译器接口 当我用 scalac 编译时 一切都按预期进行 但是当我使用 sbt 编译时 它仍然可以编译 但在执行时 它会在从 IMain
  • Slick中的动态查询参数(排序)

    我正在尝试将异常查询转换为平滑查询Play 2 3 示例之一 https github com playframework playframework tree 2 3 x samples scala computer database 但
  • 最近用 Java 编写的 FFTW 包装器

    我正在寻找最新版本的最小 Java 包装器FFTW http www fftw org FFTW 网站上列出的包装器要么已过时 jfftw 1 2 zip ftp ftp fftw org pub fftw jfftw 1 2 zip 或包
  • Scala Swing 库的问题

    您好 我在 2 8 Beta1 prerelease 版本中使用 Scala Swing 库时遇到问题 我有一种情况 我想在 GUI 中显示一个表 并在 SQL 请求返 回结果时更新它 在 Scala 中可以通过哪种方式完成此操作 目前我正
  • Scala 方法和值名称

    为什么编译失败 scala gt val a true
  • 如何让 Kotlin 类型安全构建器在 Scala 中工作?

    Kotlin 很棒类型安全的构建者 https kotlinlang org docs reference type safe builders html这使得创建像这样的 dsl 成为可能 html head title The titl
  • 返回元组的第一个元素

    假设我创建一个将两个整数相加的函数 def addInt a Int b Int Int Int val x a b x 2 我回来了 result 2 故意为了这个问题 现在我想创建一个仅返回 x 的变量 val result addIn
  • 非时间戳列上的 Spark 结构化流窗口

    我收到以下形式的数据流 id timestamp val xxx 1 12 15 25 50 1 2 12 15 25 30 1 3 12 15 26 30 2 4 12 15 27 50 2 5 12 15 27 30 3 6 12 15
  • 强制 Scala 特征实现某种方法

    有没有办法指定特征必须提供方法的具体实现 给定一些 mixin class A extends B with C foo 如果出现以下任一情况 程序将编译A B or C实施foo 但是我们如何才能强制 例如 B包含装有foo的实施 您可以
  • 自定义类上的 List.sum

    我有以下代表 GF2 字段的代码 trait GF2 def unary this def that GF2 GF2 def that GF2 GF2 def that GF2 that match case Zero gt throw n
  • ListenableFuture 到 scala Future

    我正在围绕 java 库编写一个小型 scala 包装器 java 库有一个对象 QueryExecutor 公开了 2 个方法 执行 查询 结果 asyncExecute 查询 ListenableFuture 结果 在这种情况下 Lis
  • Twitter API 与 Scala 2.12 一起使用

    我正在使用 Scala 2 12 使用 SBT 构建 构建 Spark 3 0 0 流应用程序 鉴于所有用于执行此操作的库均适用于 Scala EDIT 我尝试使用库构建时得到的示例输出 object twitter is not a me
  • 如何将 Java 字节数组转换为 Scala 字节数组?

    我是 Scala 新手 目前正在从事一个涉及 Java 和 Scala 模块的项目 现在我想使用 byte 类型的参数从 Java 调用 Scala 方法 Scala 方法的签名为 def foo data Array Byte Java
  • 将案例类传递给函数参数

    抱歉问了一个简单的问题 我想将案例类传递给函数参数 并且想在函数内部进一步使用它 到目前为止我已经尝试过这个TypeTag and ClassTag但由于某种原因 我无法正确使用它 或者可能是我没有看到正确的位置 用例与此类似 case c

随机推荐

  • 如何用matlab去修改图像尺寸

    img imread test1 jpg 这里为原始图像 i imresize img 567 390 imwrite i 1 jpg 这里为修改后图像 imread imresize和imwrite 1 imread 读取图像信息 A i
  • 查看VSCode版本

    背景 想要查看一下visual studio code的版本 方法 在vscode菜单栏 帮助 gt 发行说明 Help gt Release Notes 版本为1 36
  • C++auto_ptr的用法

    文章目录 一 auto ptr是什么 二 auto ptr需要包含的头文件 三 auto ptr用法 一 auto ptr是什么 auto ptr 是C 标准库提供的类模板 auto ptr对象通过初始化指向由new创建的动态内存 它是这块
  • TCP 协议(四)重传与超时

    1 TCP 协议中的计时器 TCP 中有四种计时器 Timer 分别为 重传计时器 Retransmission Timer 持久计时器 Persistent Timer 保活计时器 Keeplive Timer 等待计时器 Timer W
  • gdb+gdbserver远程调试技术

    首先声明 此文是在别人的基础上添加一些自己的体会 之前做嵌入式开发的时候 弄过一段时间gdb gdbserver远程调试 最后无果而终 只好将就用printf 首先感谢这篇刘品的文章 看着整洁清楚 http www cnblogs com
  • 目标检测之YOLOv3算法分析

    基本原理 特征网络 输入输出 输入 416 416 3 416 416 3 416 416 3大小的图片 不唯一 但图片大小必为32的倍数 输出3个尺度的feature map 分别为
  • 虹科分享

    说到应用程序和软件 关键词是 更多 在数字经济需求的推动下 从简化业务运营到创造创新的新收入机会 企业越来越依赖应用程序 云本地应用程序开发更是火上浇油 然而 情况是双向的 这些应用程序通常更复杂 使用的开放源代码比以往任何时候都包含更多的
  • 在Linux中使用线程

    我并不假定你会使用Linux的线程 所以在这里就简单的介绍一下 如果你之前有过多线程方面的编程经验 完全可以忽略本文的内容 因为它非常的初级 首先说明一下 在Linux编写多线程程序需要包含头文件pthread h 也就是说你在任何采用多线
  • printf()和cout的区别

    printf 和cout的区别 printf is a function that takes a variable number of arguments the first argument being a format string
  • Ubuntu使用内网穿透实现外网ssh远程登录

    Ubuntu使用内网穿透实现外网ssh远程登录 想要远程Ubuntu可以使用ssh网络协议进行远程登录 那什么时ssh呢 SSH 为 Secure Shell的缩写 由 IETF 的网络小组 Network Working Group 所制
  • Windows-tomcat 部署Java项目

    windows 通过 tomcat 部署项目 部署环境准备 JDK下载安装及配置 进入 Oracle官网 的 Java 界面 Oracle官网地址 https www oracle com java 1 JDK下载 1 1 在网站页面滚动鼠
  • 入门神经网络——浅层神经网络

    文章目录 一 基础知识 1 浅层神经网络介绍 2 浅层神经网络的正向传播 3 反向传播 二 浅层神经网络代码实例 一 基础知识 1 浅层神经网络介绍 此次构件浅层神经网络 相比于单神经元 浅层神经网络拥有多个神经元 因此又可以称为多神经元网
  • 网安等保

    欢迎关注 全栈工程师修炼指南 公众号 点击 下方卡片 即可关注我哟 设为 星标 每天带你 基础入门 到 进阶实践 再到 放弃学习 花开堪折直须折 莫待无花空折枝 作者主页 https www weiyigeek top 博客 https b
  • xshell连接Linux一直失败解决方法

    文章目录 解决对象 方法 配置 防火墙 关闭Linux防火墙 关闭Windows防火墙 xshell连接Linux一直失败解决方法 解决对象 可能出现以下两个问题 Linux防火墙已关闭和Windows防火墙已经关闭 配置好 vim etc
  • 分布式场景下基于拍卖算法的边缘智能节点任务分配

    摘 要 针对分布式场景下的边缘智能节点任务分配问题 构建了多类型的任务分配模型用于描述边缘智能节点与任务之间的关系 提出了一种基于拍卖算法的任务分配方法 智能边缘节点以动态拍卖的方式获取各自任务 基于拍卖算法的任务分配 智能边缘节点分为拍卖
  • iPad断触问题,iPencil正常,手指断触11个简便解决方法

    最开始上网搜 发现很多人都要此类情况 然后有人说是贴膜 带壳 人体导致的静电 有人说是iPad产品缺陷 有人说是接触不良 这里提供几个简便方法 有人换了三口插头 mac的充电线 链接地线可以放电 可以起到一定作用 简便方法1 一手摸pad屏
  • vue3中script setup获取动态组件component的Dom

    使用
  • MyBatis经典面试题及答案

    1 什么是MyBatis 答 MyBatis是一个可以自定义SQL 存储过程和高级映射的持久层框架 2 讲下MyBatis的缓存 答 MyBatis的缓存分为一级缓存和二级缓存 一级缓存放在session里面 默认就有 二级缓存放在它的命名
  • Composite——设计模式学习笔记

    Composite模式 一 意图 将对象组合成树形结构以表示 部分 整体 的层次结构 Composite使得用户对单个对象操作和组合对象的操作使用具有一致性 二 动机 绘图编辑器和图形捕捉系统图形应用程序中 总是存在简单的图形到简单的组件再
  • 15-Scala使用Option、Some、None,避免使用null

    1 避免null使用 大多数语言都有一个特殊的关键字或者对象来表示一个对象引用的是 无 在Java 它是null 在Java 里 null 是一个关键字 不是一个对象 所以对它调用任何方法都是非法的 但是这对语言设计者来说是一件令人疑惑的选