可变(mutable)集合与不可变(immutable)集合

为了更易于完成不可变集合到可变集合的转换,或者反向转换,Scala提供了一些语法糖。纵使不可变集和映射并不支持真正的+=方法,Scala还是为此提供了+=的语法解释。

scala> val people = Set("Nancy", "Jane")
people: scala.collection.immutable.Set[String] = Set(Nancy, Jane) scala> people += "Bob"
<console>:9: error: value += is not a member of scala.collection.immutable.Set[S
tring]
people += "Bob"
^

然而如果people声明为var,而不是val,那么集合就可以用+=操作完成“更新”,尽管它是不可变类型的。首先,新创建集合;然后,people将被重新赋值为新集合:

scala> var people = Set("Nancy", "Jane")
people: scala.collection.immutable.Set[String] = Set(Nancy, Jane) scala> people += "Bob" scala> people
res2: scala.collection.immutable.Set[String] = Set(Nancy, Jane, Bob)

同样的理念可以应用于所有以=结尾的方法,而不仅是+=方法。以下代码把该语法应用于-=操作符,从集中移除元素;以及++=操作符,把集合的所有元素添加到集里面:

scala> people -= "Jane"

scala> people ++= List("Tom", "Harry")

scala> people
res5: scala.collection.immutable.Set[String] = Set(Nancy, Bob, Tom, Harry)

这块语法糖不仅对集合有效,它还具有普适性。例如,下面是用在浮点数上的:

scala> var roughlyPi = 3.0
roughlyPi: Double = 3.0 scala> roughlyPi += 0.1 scala> roughlyPi += 0.04 scala> roughlyPi
res8: Double = 3.14

这种扩展的效果类似于Java的赋值操作符+=、-=、*=等,不过其更为通用,因为所有以=结尾的操作符都可以做转化。

初始化集合

最常见的创建和初始化集合的方法是把初始值传递给要用的集合类型的伴生对象的工厂方法。你只须把元素放在伴生对象名后面的括号中,Scala编译器就会把它转化为该伴生对象的apply方法调用:

scala> List(1, 2, 3)
res9: List[Int] = List(1, 2, 3) scala> Set('a', 'b', 'c')
res10: scala.collection.immutable.Set[Char] = Set(a, b, c) scala> import scala.collection.mutable
import scala.collection.mutable scala> mutable.Map("hi" -> 2, "there" -> 5)
res11: scala.collection.mutable.Map[String,Int] = Map(hi -> 2, there -> 5) scala> Array(1.0, 2.0, 3.0)
res12: Array[Double] = Array(1.0, 2.0, 3.0)

尽管通常都可以让Scala的编译器从传递给工厂方法的元素推断集合的元素类型,但有些时候或许你会希望指定以不同于编译器所选的类型创建集合。尤其对于可变集合来说更是如此。举例如下:

scala> import scala.collection.mutable
import scala.collection.mutable scala> val stuff = mutable.Set(42)
stuff: scala.collection.mutable.Set[Int] = Set(42) scala> stuff += "abracadabra"
<console>:11: error: type mismatch;
found : String("abracadabra")
required: Int
stuff += "abracadabra"
^

这里的问题在于stuff被指定的类型为Int。如果想要让它的类型为Any,你需要明确地说明,把元素类型放在方括号里,如下:

scala> val stuff = mutable.Set[Any](42)
stuff: scala.collection.mutable.Set[Any] = Set(42) scala> stuff += "abracadabra"
res14: stuff.type = Set(abracadabra, 42)

另一种特殊情况是,你想要把集合初始化为指定类型。例如,设想你要把列表中的元素保存在TreeSet中。列表如下:

scala> val colors = List("blue", "yellow", "red", "green")
colors: List[String] = List(blue, yellow, red, green)

你不能把colors列表传递给TreeSet工厂方法:

scala> import scala.collection.immutable.TreeSet
import scala.collection.immutable.TreeSet scala> val treeSet = TreeSet(colors)
<console>:11: error: No implicit Ordering defined for List[String].
val treeSet = TreeSet(colors)
^

实际上,需要创建空的TreeSet[String]对象并使用TreeSet的++操作符把列表元素加入其中:

scala> val treeSet = TreeSet[String]() ++ colors
treeSet: scala.collection.immutable.TreeSet[String] = TreeSet(blue, green, red,yellow)

数组与列表之间的互转

另一方面,如果你需要用集合初始化列表或数组,非常简单,直接做就是了。使用集合初始化列表,只须对集合调用toList方法:

scala> treeSet.toList
res0: List[String] = List(blue, green, red, yellow)

或者,如果需要的是数组,则调用toArray:

scala> treeSet.toArray
res1: Array[String] = Array(blue, green, red, yellow)

请牢记,转变为列表或数组同样需要复制集合的所有元素,因此对于大型集合来说可能比较慢。
集合映射的可变与不可变互转

另一种偶尔发生的情况是把可变集或映射转换成不可变类型,或者反向转换。要做到这一点,你可以利用前面以列表元素初始化TreeSet时的演示技巧。比如说你想要把当前使用的可变集合转换成不可变集合,可以先创建空的不可变集合,然后把可变集合的元素用++操作符添加进去。下面的代码说明了如何把前面例子里的不可变TreeSet转换为可变集,再转回不可变集:

scala> import scala.collection.mutable
import scala.collection.mutable scala> treeSet
res2: scala.collection.immutable.TreeSet[String] = TreeSet(blue, green, red, yel
low) scala> val mutaSet = mutable.Set.empty ++ treeSet
mutaSet: scala.collection.mutable.Set[String] = Set(red, blue, green, yellow) scala> val immutaSet = Set.empty ++ mutaSet
immutaSet: scala.collection.immutable.Set[String] = Set(red, blue, green, yellow
)

可以使用同样的技巧实现可变映射与不可变映射之间的转换:

scala> val muta = mutable.Map("i" -> 1, "ii" -> 2)
muta: scala.collection.mutable.Map[String,Int] = Map(ii -> 2, i -> 1) scala> val immu = Map.empty ++ muta
immu: scala.collection.immutable.Map[String,Int] = Map(ii -> 2, i -> 1)

scala编程第17章学习笔记(3)的更多相关文章

  1. scala编程第17章学习笔记(4)——元组

    元组可以把固定数量的条目组合在一起以便于作为整体传送.不像数组或列表,元组可以保存不同类型的对象. 元组常用来返回方法的多个值.例如,下面的方法找到集合中的最长单词并返回它的索引: scala> ...

  2. scala编程第17章学习笔记(2)——集和映射

    默认情况下在使用“Set”或“Map”的时候,获得的都是不可变对象.如果需要的是可变版本,需要先写明引用. 如果同一个源文件中既要用到可变版本,也要用到不可变版本的集合或映射,方法之一是引用包含了可变 ...

  3. scala编程第17章学习笔记(1)——集合类型

    列表 列表的初始化及对其首尾的访问: scala> val colors = List("red", "blue", "green") ...

  4. scala编程第16章学习笔记(3)——List类的高阶方法

    列表间映射:map.flatMap和foreach 1.xs map f 操作返回把函数f应用在xs的每个列表元素之后由此组成的新列表.如: scala> List(1, 2, 3) map ( ...

  5. scala编程第16章学习笔记(2)

    转换列表:toIterator, toArray,copyToArray List类的toArray方法将递归存放的列表转换为连续存放的数组 Array类的toList方法将连续存放的数组转换为递归存 ...

  6. scala编程第16章学习笔记(1)

    List列表的基本操作 head方法获得列表的第一个元素 tail方法获得列表除第一个元素之外的其它元素 isEmpty:判断列表是否为空,空的话返回真 last:获得列表最后一个元素 init:获得 ...

  7. scala编程第19章学习笔记(1)——类型参数化

    一.queues函数式队列 函数式队列是一种具有以下三种操作方式的数据结构: head 返回队列的第一个元素. tail 返回除第一个元素之外的队列. scala> import scala.c ...

  8. scala编程第18章学习笔记——有状态的对象

    银行账号的简化实现: scala> class BankAccount{ | private var bal: Int = 0 | def balance: Int = bal | def de ...

  9. scala编程第16章学习笔记(4)——List对象的方法

    通过元素创建列表:List.apply List(1, 2, 3) 等价于List.apply(1, 2, 3): scala> List.apply(1, 2, 3) res0: List[I ...

随机推荐

  1. Dubbo内核实现之SPI简单介绍

    这个部分单独写一页,看起来更高大上一些. 1.概括 Dubbo采用微内核+插件体系,使得设计优雅,扩展性强.那所谓的微内核+插件体系是如何实现的呢! 即我们定义了服务接口标准,让厂商去实现(如果不了解 ...

  2. modCount干嘛的

    在ArrayList.LinkedList.HashMap等等的内部增删改中我们总能看到modCount的身影,modCount字面意思就是修改次数,但为什么要记录modCount的修改次数呢? 大家 ...

  3. react篇章-事件处理

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title&g ...

  4. HDU - 1716 排列2 水题

    排列2 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  5. JAVAEE——ssm综合练习:CRM系统(包含ssm整合)

    1 CRM项目外观   1. 开发环境 IDE: Eclipse Mars2 Jdk: 1.7 数据库: MySQL 2. 创建数据库 数据库sql文件位置如下图: 创建crm数据库,执行sql 效果 ...

  6. Kubernetes(k8s)集群部署(k8s企业级Docker容器集群管理)系列之flanneld网络介绍及部署(三)

    0.前言 整体架构目录:ASP.NET Core分布式项目实战-目录 k8s架构目录:Kubernetes(k8s)集群部署(k8s企业级Docker容器集群管理)系列目录 一.flanneld介绍 ...

  7. MacBook Apache服务

    想着如何在Mac OS下部署静态网页(纯粹的html,css,js),用惯了windows下的iis,可惜Mac OS下也许只能通过Tomcat或者Apache之类的作为部署容器.听说Mac OS下自 ...

  8. 【SQL】185. Department Top Three Salaries

    The Employee table holds all employees. Every employee has an Id, and there is also a column for the ...

  9. Django 模板中使用css, javascript

    Django 模板中使用css, javascript (r'^css/(?Ppath.*)$', 'django.views.static.serve', {'document_root': '/v ...

  10. MongoDB复制原理

    ##mongodb复制(主从服务器数据备份, 一个主服务器可以有很多个从服务器) #mongodb的复制至少需要两个节点.其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据 ...