Scala学习8 – Set和Map
GuaTompson
9年前
<h2>概述</h2> <p>先来看张图:</p> <p><img src="https://simg.open-open.com/show/eea7f8fbb7932acedcc662be2e739887.png"></p> <p>这个很像Java的UML图。勉强按UML图来理解下。这张图里有几个比较有趣的地方:</p> <ul> <li>一个新的概念——trait;</li> <li>Set和Set、Set和HashSet全部都是继承关系;</li> <li>提供了immutable和mutable两套集合方案。</li> </ul> <p>接下来挨个解释下。</p> <h2>trait</h2> <p>trait翻译为中文意思是“特质”。在trait中封装了方法和字段的定义,并且可以多继承,这个类似于Java中的接口。但是和Java中的接口不同的是:scala中trait的定义除了使用关键字trait外,其他与类定义无异。</p> <p>关于trait先就说这些,以后再慢慢说。</p> <h2>关于继承</h2> <p>这里让我觉得比较奇怪的是scala.collection.immutable.HashSet和scala.collection.immutable.Set的关系居然是继承。我找了张Java中集合的类图,来看一下:</p> <p><img src="https://simg.open-open.com/show/c80aa3ccf03af2c877fe1032fdacc543.jpg"></p> <p>与上图比较可以看到有明显的不同:在Java中常用的集合类通常是实现指定的接口,是implements而非是extends。也许scala中并没有implements这样的机制。不管怎样,这个都只能留到以后见分晓了。</p> <h2>immutable和mutable的Set</h2> <p>Scala为Set提供了两个trait,分别是可变和不可变的。因此如果想要使用scala中的HashSet,可以根据需要选择可变与不可变的具体实现类。默认的Set是不可变的,需要使用可变Set时需要使用import关键字显式引入或者使用全限定类名。看一下下面这段代码:</p> <pre> def testImmutableSet(){ var immutableSet = Set("zhyea.com", "robin") immutableSet+="zhang" println(immutableSet) } def testMutableSet(){ var mutableSet = scala.collection.mutable.Set("zhyea.com", "robin") mutableSet+="zhang" println(mutableSet) } </pre> <p>上面的第一个方法使用了不可变Set,第二个方法使用了可变Set,执行结果都差不多(请忽略第一行的“Hello World!”):</p> <p><img src="https://simg.open-open.com/show/43759937fa3ab54d0c208e70ed9a4fa6.png"></p> <p>虽然结果差不多,但是还是有些不同的:不可变Set中没有提供“+=”这样的方法,可变Set提供了“+=”方法,不可变Set的“+=”运算实际上是Set1 = Set1 + Set2。至于为什么Set中的元素输出顺序会不一样,还是留着以后去分析好了(现在我看Scala的SDK源码有种看天书的感觉)。</p> <p>目前还有一点让我比较疑惑,就是可变Set和不可变Set的“+”方法,可变Set调用“+”方法后集合的长度居然没有发生变化:</p> <pre> def testImmutableSet(){ var immutableSet = Set("zhyea.com", "robin") immutableSet + "zhang" println(immutableSet) } def testMutableSet(){ var mutableSet = scala.collection.mutable.Set("zhyea.com", "robin") mutableSet + "zhang" println(mutableSet) } </pre> <p>执行结果:</p> <p><img src="https://simg.open-open.com/show/b0b619a119d33caee40836511d9cf3e6.png"></p> <p>看了下“+”方法的描述,是创建了一个新的对象:</p> <pre> /** Creates a new set consisting of all the elements of this set and `elem`. * * $addDuplicates * * @param elem the element to add. * @return a new set consisting of elements of this set and `elem`. */ @migration("`+` creates a new set. Use `+=` to add an element to this set and return that set itself.", "2.8.0") override def + (elem: A): This = clone() += elem </pre> <h2>Map</h2> <p>Map和Set类似,采用继承机制和trait提供了两种版本的Map:</p> <p><img src="https://simg.open-open.com/show/1edeb5e0487c1b6cbd5d1327c57cfd2a.png"></p> <p>可变的Map在scala.collection.mutable里面,不可变的Map在scala.collection.immutable里面。</p> <p>下面是一段可变Map的使用示例:</p> <pre> val mutableMap = scala.collection.mutable.Map[Int, String](); mutableMap += (1 -> "zhyea.com") mutableMap += (2 -> "robin") println(mutableMap(2)) </pre> <p>在代码的第一行里使用可变Map的全限定类名定义了一个val变量(因为使用的Map是可变的,所以可以将变量定义为val类型)。第二行使用了“->”和“+=”方法为mutableMap变量添加元素。前面提过Scala编译器把1->”zhyea.com”这样的二元操作符表达式转译为(1).->”zhyea.com”,即在Int型的值1上调用它的“->”方法,并传入参数“zhyea.com”,这个方法的返回值是一个包含键值对的二元元组。然后这个二元元组会被传递给mutableMap的“+=”方法。看一下最后的打印结果,这里输出了键值为2的值:</p> <p><img src="https://simg.open-open.com/show/38842b700842529258ea014e49ee1482.png"></p> <p>不可变Map是缺省的可以直接使用,看一下下面这段代码:</p> <pre> val immutableMap = Map(1 -> "zhyea.com", 2 -> "robin") println(immutableMap(2)) </pre> <p>再来看一下这两次Map的初始化。第一次在定义mutableMap的时候显式指明了类型参数;第二次因为提供了初始化元素,所以scala编译器可以通过元素推断出immutableMap的类型参数。第一次的mutableMap也可以这样定义:</p> <pre> val mutableMap = scala.collection.mutable.Map(3 -> "zhyea.com"); </pre> <p>就这样。</p> <p>来自: <a href="/misc/goto?guid=4959670877453447627" rel="nofollow">http://www.zhyea.com/2016/04/15/scala-8-set-and-map.html</a></p>