我们已经知道List(1, 2, 3)可以创建出含有三个元素的列表,用Map('A' -> 1, 'C' -> 2)可以创建含有两对绑定的映射。实际上各种Scala容器都支持这一功能。任意容器的名字后面都可以加上一对带参数列表的括号,进而生成一个以这些参数为元素的新容器。不妨再看一些例子:
Traversable() // 一个空的Traversable对象List() // 空列表List(1.0, 2.0) // 一个以1.0、2.0为元素的列表Vector(1.0, 2.0) // 一个以1.0、2.0为元素的VectorIterator(1, 2, 3) // 一个迭代器,可返回三个整数Set(dog, cat, bird) // 一个包含三个动物的集合HashSet(dog, cat, bird) // 一个包含三个同样动物的HashSetMap('a' -> 7, 'b' -> 0) // 一个将字符映射到整数的Map实际上,上述每个例子都被“暗地里”转换成了对某个对象的apply方法的调用。例如,上述第三行会展开成如下形式:
List.apply(1.0, 2.0)可见,这里调用的是List类的伴生对象的apply方法。该方法可以接受任意多个参数,并将这些参数作为元素,生成一个新的列表。在Scala标准库中,无论是List、Stream、Vector等具体的实现类还是Seq、Set、Traversable等抽象基类,每个容器类都伴一个带apply方法的伴生对象。针对后者,调用apply方法将得到对应抽象基类的某个默认实现,例如:
scala > List(1,2,3)res17: List[Int] = List(1, 2, 3)scala> Traversable(1, 2, 3)res18: Traversable[Int] = List(1, 2, 3)scala> mutable.Traversable(1, 2, 3)res19: scala.collection.mutable.Traversable[Int] = ArrayBuffer(1, 2, 3)除了apply方法,每个容器类的伴生对象还定义了一个名为empty的成员方法,该方法返回一个空容器。也就是说,List.empty可以代替List(),Map.empty可以代替Map(),等等。
Seq的子类同样在它们伴生对象中提供了工厂方法,总结如下表。简而言之,有这么一些:
concat,将任意多个Traversable容器串联起来fill 和 tabulate,用于生成一维或者多维序列,并用给定的初值或打表函数来初始化。 range,用于生成步长为step的整型序列,并且iterate,将某个函数反复应用于某个初始元素,从而产生一个序列。