Scala的存在类型

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

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

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

简写 完整形式 描述
Seq[_] Seq[T] forSome {type T} T 可以是Any 的任意子类
Seq[_ <: A] Seq[T] forSome {type T <: A} T 可以是A(在某处已经定义了)的任意子类
Seq[_ >: Z <: A] Seq[T] forSome {type T >: Z <: A} T 可以是A 的子类且是Z 的超类

上面的表格以常用的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 and
def double(seq: Seq[Int]): Seq[Int] at line 13
have same type after erasure: (seq: Seq)Seq
def 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] 的表达式在结构上与Java 的表达式java.util.List<? extends A>的类似之处。

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

更多教程请参考 flydean的博客

Scala的存在类型的更多相关文章

  1. 第54讲:Scala中复合类型实战详解

    今天学习了scala的复合类型的内容,让我们通过实战来看看代码: trait Compound_Type1trait Compound_Type2class Compound_Type extends ...

  2. 第53讲:Scala中结构类型实战详解

    今天学习了scala的结构类型,让我们看看代码 class Structural {def open() = print("A class interface opened") } ...

  3. Scala 深入浅出实战经典 第54讲:Scala中复合类型实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  4. Scala 深入浅出实战经典 第53讲:Scala中结构类型实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  5. Scala的Option类型

    Scala的Option类型 为了让所有东西都是对象的目标更加一致,也为了遵循函数式编程的习惯,Scala鼓励你在变量和函数返回值可能不会引用任何值的时候使用Option类型.在没有值的时候,使用No ...

  6. 【scala】基础类型

    基础类型                              位数 Boolean                                 - Byte                 ...

  7. scala如何解决类型强转问题

    scala如何解决类型强转问题 scala属于强类型语言,在指定变量类型时必须确定数据类型,即便scala拥有引以为傲的隐式推到,这某些场合也有些有心无力. 例如: java同属强类型语言,但java ...

  8. Scala的Higher-Kinded类型

    Scala的Higher-Kinded类型 Higher-Kinded从字面意思上看是更高级的分类,也就是更高一级的抽象.我们先看个例子. 如果我们要在scala中实现一个对Seq[Int]的sum方 ...

  9. Scala的自定义类型标记

    Scala的自定义类型标记 Scala中有很多千奇百怪的符号标记,看起来是那么的独特,就像是一杯dry martini-好像黑夜中的萤火虫,那么耀眼,那么出众. 好了言归正传,这一篇文章我们会讲一下S ...

随机推荐

  1. Blazor入门笔记(5)-数据绑定

    1.环境 VS2019 16.5.1 .NET Core SDK 3.1.200 Blazor WebAssembly Templates 3.2.0-preview2.20160.5 2.默认绑定 ...

  2. VAuditDemo-文件包含漏洞的审计

    包含漏洞 include.require等先关函数,include($file) 文件包含漏洞的问题在于参数可控(路径.文件名.后缀) include($path.$filename.$ext) 包含 ...

  3. C#与html实现WebSocket交互(制作ktv手机点歌)

    ------------恢复内容开始------------ C#与html实现WebSocket交互(制作ktv手机点歌) C#端代码 static void Main(string[] args) ...

  4. go 内存优化

    一.斐波那切数列优化 package main import ( "time" "fmt" ) const LIM = 41 var fibs [LIM]uin ...

  5. Flask 入门(七)

    flask操作数据库:建表: 承接上文: 修改main.py中的代码如下: #encoding:utf-8 from flask_sqlalchemy import SQLAlchemy from f ...

  6. 汇编刷题 已知整数变量A和B,试编写完成下列操作的程序

    1.若两个数中有一个是奇数,一个是偶数,则将它们互换储存地址 2.若两个数都是奇数,则分别加一 3.若两个数都是偶数,则不变 DATA SEGMENT A DB 12H B DB 25H DATA E ...

  7. Docker-Bridge Network 01 容器间通信

    本小节介绍bridge network模式下,单机上的容器网络拓扑及通信. 1.前言 对于单机上的容器,Docker提供了bridge.host.none三种网络.我们首先介绍经典的bridge模式. ...

  8. uni-app同步缓存值 设置 读取 删除

    A页面 <view class="go-to-tab" @tap="gotologin"> 去login页面 </view> msg : ...

  9. Java 基础增强

    jdk与jre 要想深入了解Java必须对JDK的组成, 本文对JDK6里的目录做了基本的介绍,主要还是讲解 了下JDK里的各种可执行程序或工具的用途 Java(TM) 有两个平台 JRE 运行平台, ...

  10. three.js - 一个javascript 3D代码库

    这个项目的目的是用最简单的开发模式创建一个轻量级的3 d代码库,这个js库提供了canvas,svg,css3d和webgl这四种渲染方式. 下载地址: 下载地址:https://github.com ...