Scala的存在类型

作者: flydean程序那些事 | 来源:发表于2020-02-01 10:08 被阅读0次

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的存在类型

    Scala的存在类型 存在类型也叫existential type,是对类型做抽象的一种方法。可以在你不知道具体类...

  • -6- 类型层次结构

    [参考link] Scala类型层次结构 与Java不同,Scala中没有原生类型。Scala中的所有数据类型都是...

  • Scala相关文章索引(2)

    基本常识 scala编程第17章学习笔记(1)——集合类型 scala Map类型笔记 scala代码风格指南--...

  • 快学Scala读书笔记

    scala不刻意区分原生类型和引用类型 scala单参数方法可以用运算符形式调用,例如: scala没有提供"++...

  • Scala教程之:Enumeration

    Enumeration应该算是程序语言里面比较通用的一个类型,在scala中也存在这样的类型, 我们看下Enume...

  • -7- scala数据类型

    [参考link] Scala 布尔类型 布尔类型限于文本true或文本false,如下面的示例所示: Scala ...

  • Scala 之旅(TOUR OF SCALA)——统一类型(UN

    在 Scala 中,所有的值都有类型,包括数值和函数。下面这个图表说明了类型继承结构的子集。 Scala 类型继承...

  • Essential Scala: Literals

    Scala对象系统 总体上,Scala对象系统可分为两类: 引用类型 值类型 引用类型 AnyRef的子类 使用n...

  • Scala泛型

    泛型类是以类型作为参数,Scala类型参数放在方括号[]中,Java放在<>中 变型 Variance Scala...

  • Scala 的类型推断

    Scala 的类型推断 按照官方的说法,Scala 的类型推断是基于流(flow based)的,假设有方法如下:...

网友评论

    本文标题:Scala的存在类型

    本文链接:https://www.haomeiwen.com/subject/qomtxhtx.html