存在类型也叫existential type,是对类型做抽象的一种方法。可以在你不知道具体类型的情况下,就断言该类型存在。

存在类型用_来表示,你可以把它看成java中的?。

下面是存在类型的具体例子:

简写完整形式描述Seq[_]Seq[T] forSome {type T}T 可以是Any 的任意子类Seq[_ <: a forsome t>: Z <: a forsome t>: Z <: a>

上面的表格以常用的Seq为例,列举了存在类型的例子。

那么为什么会需要存在类型呢?

如果我们有一个List[A],我们需要两个版本的double函数,一个版本接受List[Int]并返回新的List[Int]*2,另外一个版本接受List[String], 并通过对整数调用toInt,将字符串转换为Int,然后调用第一个版本的double函数。

我们可能会这样写:

object Doubler {def double(seq: Seq[String]): Seq[Int] = double(seq map (_.toInt))def double(seq: Seq[Int]): Seq[Int] = seq map (_*2)}

上面的程序看起来是没问题的,但是编译却失败。

Error:(3, 7) double definition:def double(seq: Seq[String]): Seq[Int] at line 12 anddef double(seq: Seq[Int]): Seq[Int] at line 13have same type after erasure: (seq: Seq)Seqdef double(seq: Seq[Int]): Seq[Int] = seq map (_*2)

问题就在于编译过程中的类型擦除,也就是在编译成字节码过后,定义的泛类型将会被删除。那么最后Seq[String]和Seq[Int]都会被编译成Seq,最终导致两个方法拥有同样的参数列表,最终编译报错。

既然有类型擦除的问题,那么我们考虑定义一个double方法,在double方法内部进行类型的判断:

object Doubler {  def double(seq: Seq[_]): Seq[Int] = seq match {    case Nil => Nil    case head +: tail => (toInt(head) * 2) +: double(tail)  }  private def toInt(x: Any): Int = x match {    case i: Int => i    case s: String => s.toInt    case x => throw new RuntimeException(s"Unexpected list element $x")  }}

为什么我们需要使用Seq[_]呢? 我们看一下Seq类型的定义:

type Seq[+A] = scala.collection.Seq[A]

从定义我们知道,Seq类型一定是需要一个类型参数的,如果我们这样写:

  def double(seq: Seq): Seq[Int] = seq match {    case Nil => Nil    case head +: tail => (toInt(head) * 2) +: double(tail)  }

则会编译出错,因为tail是Seq[A]类型的,但是double需要一个Seq类型。

使用Seq[_]表示,Seq[T] forSome {type T}。虽然我不知道Seq里面具体是哪种类型,但是肯定是有类型的。

可以对比一下java.util.List[_ <: a>

你会在scala代码中看到很多Seq[_]的代码,存在类型的主要目的是为了兼容java代码。

欢迎关注我的公众号:程序那些事,更多精彩等着您!

更多内容请访问:flydean的博客 flydean.com

scala 定义空list_Scala的存在类型相关推荐

  1. scala 定义空list_四十二、Scala 教程: List(列表)

    列表 Scala 列表 有点像 数组, 因为他们都是有序存储结构,而且所有元素的类型都一样,但它又不同于数组 1. 列表(List)一旦被创建就不能改变其中的元素. 2. 列表(List)底层的数据结 ...

  2. scala 定义空的list_18.scala的型变

    型变是复杂类型的子类型关系与其组件类型的子类型关系的相关性.Scala支持 泛型类 的类型参数的型变注释,允许它们是协变的,逆变的,或在没有使用注释的情况下是不变的.在类型系统中使用型变允许我们在复杂 ...

  3. java按条件查询结果为空_mybatis中查询结果为空时不同返回类型对应返回值问题...

    今天在别人的代码基础上实现新需求,看到对于mybatis查询结果的判断不是很正确,如果查询结果为空就会异常,不知道大家有没有这样的疑惑:mybatis中resultType有多种返回类型,对于每种不同 ...

  4. Qt (高仿Visio)流程图组件开发(三) 图元基类如何定义,流程图多种图元类型实现

    文章目录 本系列目录 前言 一.图元基类的定义 1.图元信息基类结构体 2.图元位置 3.父子对象关系 二.自定义图元实现 1.自定义图元基类(FlowchartGraphicsItem)与Qt原生图 ...

  5. python 定义空集合 和定义空字典的

    python 中定义空集合 使用set 方法 list_a = set() # 定义一个空的集合 python中定义空字典使用 {} 或则使用dict() list_b = {} # 定义一个空的字典 ...

  6. Java定义接口变量为接收类型有什么好处(面向接口编程)

    个人理解:定义接口变量为接收类型属于面向接口的编程,通过接口的抽象能减少类之间的耦合,增加可复用性. 面向接口编程: 一种规范约束 制定者(或者叫协调者),实现者(或者叫生产者),调用者(或者叫消费者 ...

  7. 函数式编程之-拒绝空引用异常(Option类型)

    函数式编程之-拒绝空引用异常(Option类型) 参考文章: (1)函数式编程之-拒绝空引用异常(Option类型) (2)https://www.cnblogs.com/xiandnc/p/9332 ...

  8. php 怎么定义一个空对象,php定义空对象的方法

    本文主要和大家分享php定义空对象的方法,有时候我们直接对不存在的数组直接定义其下标的值,不会报错,但是我们定义不存在的对象的时候,就会报错,这个时候我们定义一个空对象即可.有以下三种方法:<? ...

  9. 定义一个泛型为String类型的List集合,统计该集合中每个字符 (注意,不是字符串)出现的次数。例如:集合中有”abc”、”bcd”两个元素, 程序最终输出结果为:

    代码 import java.util.*;/*6.定义一个泛型为String类型的List集合,统计该集合中每个字符(注意,不是字符串)出现的次数.例如:集合中有"abc".&q ...

最新文章

  1. php实现微信企业向用户付款
  2. 零基础Java学习之构造器
  3. 用Tableau制作滚动时间轴(上)
  4. 基于Vmware player的Windows 10 IoT core + RaspberryPi2安装部署
  5. IntelliJ IDEA中右键新建时,选项没有Java class的解决方法和具体解释
  6. 合理的嵌入式开发学习路线
  7. Blazor University (10)组件 — 捕获意外参数
  8. python可以用来编写计算机网络程序吗_计算机网络(基于python做的笔记 )
  9. c mysql数据库_C实现MySQL数据库操作
  10. ubuntu 下 Graphviz 的安装及神经网络的绘图
  11. python变量赋值给数组_python 变量,数组,字符串
  12. bzoj3944 Sum
  13. 用数字计算机公式表白,数学计算题表白公式
  14. 正确写理想的学术论文英文摘要
  15. php微信退款结果通知,微信支付退款结果通知解密
  16. 计算机大三学生怎么找实习工作?学了计算机很迷茫怎么办?
  17. 做个合格的吃货~利用Python爬取美食网站3032个菜谱并分析
  18. 前端项目如何向一个后端项目传递数组?(批量删除如何传参)
  19. idea恢复被覆盖的本地未提交代码
  20. TM1638 LED数码显示模块ARDUINO驱动代码

热门文章

  1. EasyX制作掩码图
  2. Linux之脚本执行
  3. Tomcat启动窗口
  4. MySQL创建视图的语法格式
  5. ASP.NET的命名空间
  6. h5 跳转上个页面刷新_关于javascript跳转与返回和刷新页面
  7. hub设备_HUB选择困难症?从这里解决
  8. 怎样查看电脑系统版本_微信7.0.0自动更新后怎样去还原以前的旧版本?
  9. SpringBoot 2.0 教程实战 MySQL 读写分离
  10. 蓝桥杯java第八届第八题--包子凑数