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>