Scala的存在类型
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的存在类型的更多相关文章
- 第54讲:Scala中复合类型实战详解
今天学习了scala的复合类型的内容,让我们通过实战来看看代码: trait Compound_Type1trait Compound_Type2class Compound_Type extends ...
- 第53讲:Scala中结构类型实战详解
今天学习了scala的结构类型,让我们看看代码 class Structural {def open() = print("A class interface opened") } ...
- Scala 深入浅出实战经典 第54讲:Scala中复合类型实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Scala 深入浅出实战经典 第53讲:Scala中结构类型实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Scala的Option类型
Scala的Option类型 为了让所有东西都是对象的目标更加一致,也为了遵循函数式编程的习惯,Scala鼓励你在变量和函数返回值可能不会引用任何值的时候使用Option类型.在没有值的时候,使用No ...
- 【scala】基础类型
基础类型 位数 Boolean - Byte ...
- scala如何解决类型强转问题
scala如何解决类型强转问题 scala属于强类型语言,在指定变量类型时必须确定数据类型,即便scala拥有引以为傲的隐式推到,这某些场合也有些有心无力. 例如: java同属强类型语言,但java ...
- Scala的Higher-Kinded类型
Scala的Higher-Kinded类型 Higher-Kinded从字面意思上看是更高级的分类,也就是更高一级的抽象.我们先看个例子. 如果我们要在scala中实现一个对Seq[Int]的sum方 ...
- Scala的自定义类型标记
Scala的自定义类型标记 Scala中有很多千奇百怪的符号标记,看起来是那么的独特,就像是一杯dry martini-好像黑夜中的萤火虫,那么耀眼,那么出众. 好了言归正传,这一篇文章我们会讲一下S ...
随机推荐
- Spring Boot创建一个HelloWorld项目
目录 Spring Boot 简介 微服务框架 以前使用spring开发web的方式 Spring Boot 启动器介绍 如何创建一个helloword的SpringBoot项目 Spring Boo ...
- 听说你还搞不定java中的==和equals?
相信很多读者关于==和equals懂了又懵,懵了又懂,如此循环,事实上可能是因为看到的博客文章之类的太多了,长篇大论,加上一段时间的洗礼之后就迷路了.本篇文章再一次理清楚.当然如果觉得本文太啰嗦的话, ...
- Java – Try with Resources
1.介绍 Java 7中引入的对try-with-resources的支持使我们能够声明将在try块中使用的资源,并确保在执行该块后将关闭资源. ⚠️:声明的资源必须实现AutoCloseable接口 ...
- python爬虫之requests的高级使用
1.requests能上传文件 # 导入requests模块 import requests # 定义一个dict files = {'file': open('D:/360Downloads/1.t ...
- JavaScript布尔操作符
布尔操作符 逻辑与 (&&) 逻辑与操作可以应用于任何类型的操作数,当有一个操作数不是布尔值的情况下,逻辑与操作就不一定返回布尔值 如果第一个操作数是对象,则返回第二个操作数 如果第二 ...
- 这些基本的 HTML5 标签你不能不知道
HTML5元素 HTML5是HTML最新的修订版本,2014年10月由万维网联盟(W3C)完成标准制定. HTML5是用来写网页的一门标记语言. 使用的时候需要在首行声明HTML,如:<!DOC ...
- 玩转redis-延时消息队列
上一篇基于redis的list实现了一个简单的消息队列:玩转redis-简单消息队列 源码地址 使用demo 产品经理经常说的一句话,我们不光要有X功能,还要Y功能,这样客户才能更满意.同样的,只有简 ...
- lr事务
事务:transaction(性能里面的定义:客户机对服务器发送请求,服务器做出反应的过程) 用于模拟用户的一个相对完整的业务操作过程:如登录,查询,交易等操作(每次http请求不会用来作为一个事务) ...
- Mac OS安装docker
MacOS Docker 安装 使用 Homebrew 安装 macOS 我们可以使用 Homebrew 来安装 Docker. Homebrew 的 Cask 已经支持 Docker for Mac ...
- Wpf之HandyControls与MaterialDesign混用之DataGrid
首先在App.Xaml引入相关资源 <Application.Resources> <ResourceDictionary> <ResourceDictionary.Me ...