使用 Seq(1,2,3) 创建 Seq 对象时会发生什么?

What happens when you create a Seq object with Seq(1,2,3)?

计算表达式时究竟发生了什么:Seq(1,2,3)?

我是 Scala 的新手,现在对各种集合类型有点困惑。 Seq 是一种特质,对吧?所以当你这样称呼它时 Seq(1,2,3) 它一定是某种伴随对象?或不?它是某种扩展 Seq 的 class 吗?最重要的是返回值的类型是什么?是 Seq 吗?如果是,为什么不明确地使用扩展名 class?

同样在 REPL 中,我看到求值表达式的内容实际上是一个 List(1,2,3),但类型显然是 Seq[Int]。为什么不是像 Vector 这样的索引集合类型?这背后的逻辑是什么?

Seqval 的:

package object scala {
...
  val Seq = scala.collection.Seq
...
}

它指向对象 scala.collection.Seq:

/** $factoryInfo
 *  The current default implementation of a $Coll is a `List`.
 *  @define coll sequence
 *  @define Coll `Seq`
 */
object Seq extends SeqFactory[Seq] {
  /** $genericCanBuildFromInfo */
  implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Seq[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]

  def newBuilder[A]: Builder[A, Seq[A]] = immutable.Seq.newBuilder[A]
}

并且当您执行 Seq(1,2,3) 时,apply() 方法从 scala.collection.generic.GenericCompanion 抽象 class:

中调用
/** A template class for companion objects of "regular" collection classes
 *  represent an unconstrained higher-kinded type. Typically
 *  such classes inherit from trait `GenericTraversableTemplate`.
 *  @tparam  CC   The type constructor representing the collection class.
 *  @see [[scala.collection.generic.GenericTraversableTemplate]]
 *  @author Martin Odersky
 *  @since 2.8
 *  @define coll  collection
 *  @define Coll  `CC`
 */
abstract class GenericCompanion[+CC[X] <: GenTraversable[X]] {
...
  /** Creates a $coll with the specified elements.
   *  @tparam A      the type of the ${coll}'s elements
   *  @param elems  the elements of the created $coll
   *  @return a new $coll with elements `elems`
   */
  def apply[A](elems: A*): CC[A] = {
    if (elems.isEmpty) empty[A]
    else {
      val b = newBuilder[A]
      b ++= elems
      b.result()
    }
  }
}

最后,这个方法通过上面提到的代码构建了一个Seq类型的对象

And most importantly what is the type of the returned value?

object MainClass {

  def main(args: Array[String]): Unit = {

    val isList = Seq(1,2,3).isInstanceOf[List[Int]]

    println(isList)
  }
}

打印:

true

所以,类型是scala.collection.immutable.List

Also in REPL I see that the contents of the evaluated expression is actually a List(1,2,3), but the type is apparently Seq[Int].

上面提到的代码Seq的默认实现是List

Why is not an Indexed collection type, like Vector? What is the logic behind all that?

因为不可变的设计。该列表是不可变的,并使其不可变并具有恒定的前置操作,但 O(n) 追加操作成本和 O(n) 访问第 n 个元素的成本。 Vector 具有持续有效的访问和通过 id、前置和追加操作添加元素的实现。

要更好地了解 List 在 Scala 中的设计方式,请参阅 https://mauricio.github.io/2013/11/25/learning-scala-by-building-scala-lists.html

What exactly happens when you evaluate expression: Seq(1,2,3)?

在 Scala 中,foo(bar)foo.apply(bar) 的语法糖,除非 this 也有一个名为 foo 的方法,在这种情况下它是对隐式 this 接收者,即就像 Java,它等同于 this.foo(bar).

就像任何其他 OO 语言一样,方法调用的接收者 单独 决定如何处理该调用,因此在这种情况下,Seq 决定要做什么做。

Seq is a trait, right?

标准库中有两个Seq

So when you call it like that Seq(1,2,3) it must be some kind of a companion object? Or not?

是的,它必须是一个对象,因为您只能调用对象的方法。您不能在类型上调用方法,因此,当您看到方法调用时,它必须 是一个对象。总是。所以,在这种情况下,Seq 不可能Seq特征,它必须是Seq对象。

请注意 "it must be some kind of a companion object" 不正确。从那段代码中您唯一可以看到的是 Seq 是一个对象。您无法从那段代码知道它是否是伴随对象。为此,您必须查看源代码。在这种特殊情况下,事实证明它 ,实际上是一个伴随对象,但您不能从您显示的代码中得出结论。

Is it some kind of a class that extends Seq?

没有。它 不可能 是 class,因为你只能调用对象的方法,而 classes 在 Scala 中不是对象。 (这不像 Ruby 或 Smalltalk,其中 classes 也是 Class class 的对象和实例。)它 必须 是一个对象。

And most importantly what is the type of the returned value?

找出答案的最简单方法是简单地查看 the documentation for Seq.apply:

def apply[A](elems: A*): Seq[A]

Creates a collection with the specified elements.

  • A: the type of the collection's elements
  • elems: the elements of the created collection
  • returns a new collection with elements elems

因此,如您所见,Seq.apply 的 return 类型是 Seq,或更准确地说,Seq[A],其中 A 是表示集合元素类型的类型变量。

Is it Seq and if yes, why is not explicitly the extension class instead?

因为没有扩展名class。

此外,Scala 中的标准设计模式是伴生对象的 apply 方法 return 是伴生对象 class 或特征的实例。打破这个约定会很奇怪和令人惊讶。

Also in REPL I see that the contents of the evaluated expression is actually a List(1,2,3), but the type is apparently Seq[Int].

静态类型Seq[Int]。这就是您需要知道的全部内容。这就是您可以知道的全部内容。

现在,Seq 是一个 trait,并且无法实例化特征,因此 运行时类型 将是 class 的某个子class Seq。但!你不能也不应该关心它是什么特定的运行时类型。

Why is not an Indexed collection type, like Vector? What is the logic behind all that?

你怎么知道下次你调用它时它不会 return a Vector?一点都不重要,因为静态类型是 Seq 因此你只能调用它的 Seq 方法,你只能依赖 [=17= 的契约],即 Seq 的 post-conditions,不变量等。即使 如果 你知道它是 Vector returned,你将无法利用这些知识做任何事情。

因此,Seq.apply return 可能是最简单的事情 return,那就是 List