Scala中Seq无new关键字实例化的实现原理是什么?
好问题!这其实是Scala集合库设计里一个非常实用的小技巧,结合了伴生对象工厂方法和面向抽象编程的思想,我来给你拆解清楚:
1.
Seq(...) 根本不是在实例化trait 首先你要明确:trait Seq本身确实是抽象的,不能直接用new实例化。但当你写Seq(1, 2, 3)时,你调用的不是trait Seq的构造器,而是Seq伴生对象的apply方法——这是Scala里专门用来做对象创建的工厂方法。
2. 伴生对象帮你选好了具体实现
Seq的伴生对象(准确说是scala.collection.immutable.Seq的伴生对象,因为默认导入的是不可变集合)的apply方法会自动帮你选择合适的具体子类实例。默认情况下,它返回的是List(更准确地说是::,也就是List的链表节点类)。
你可以在Scala REPL里验证这一点:
scala> Seq(1,2,3).getClass val res0: Class[_ <: Seq[Int]] = class scala.collection.immutable.$colon$colon
输出里的$colon$colon就是Scala中List的具体实现类,它是trait Seq的子类。
3. 为什么要这么设计?
这完全是为了面向抽象编程的便利性:
- 你只需要关心
Seq这个抽象接口提供的方法(比如map、filter、fold),不用纠结具体用哪个实现类; - 如果后续需要切换实现(比如换成可变的
ArrayBuffer),只需要改成scala.collection.mutable.Seq(1,2,3)就行,业务代码不用动——因为mutable.Seq的伴生对象会返回对应的可变实现。
类似的模式在Scala里非常常见,比如Option(...)、Set(...)都是用伴生对象的工厂方法来隐藏具体实现的细节。
内容的提问来源于stack exchange,提问作者More Than Five
相关产品推荐
相关产品推荐

