【问题标题】:Concrete and abstract Vector classes具体和抽象 Vector 类
【发布时间】:2020-08-26 00:12:44
【问题描述】:

我通过scaladoc 发现了一些我觉得奇怪且无法解释的东西。 有

sealed abstract class Vector 

与其同伴object Vector。 翻看Vector.scala,似乎发生了以下情况

val test: Vector[Int] = Vector(1,2,3)

这里我调用伴随对象的 apply 方法,它使用一些工厂方法来创建一个对象,该对象是Vector 的子类并具有具体实现。所以真正的测试类型不是Vector[Int],而是其他一些子类。

当我现在打印课程时

print(test.getClass()) 

它返回Vector,这是一个抽象类,所以对象不能是Vector类型。

有没有办法打印对象的实际类?类似于我创建自己的类而没有覆盖 toString 时,scala 使用 Any(?)toString 实现来打印出 myClass@memorLocation

【问题讨论】:

  • @LuisMiguelMejíaSuárez 文档确实说它是一个密封的抽象类,对吧?至于打印类,你可以使用test.getClass().getName()
  • @user 哦,抱歉,我刚刚在我的电脑上再次打开文档,我看到了sealed abstract class 部分(出于某种原因,移动端它只是说class .无论如何,在那之后我打开了一个 REPL (version 2.13.2) 并执行test.getClass.getCanonicalName 返回scala.collection.immutable.Vector1 这与您的直觉一致,有不同的类别 矢量。因此,您必须检查两个不同版本的文档和代码,例如在2.13.2 中引入了一个新版本的 Vector,可能在它只是一个普通类之前?
  • 是的,例如在2.12 上它是final class: scala-lang.org/files/archive/api/2.12.10/scala/collection/… 并且实际上,在2.12 上打印类名给出scala.collection.immutable.Vector
  • 一定是我的“REPL”。我正在使用带有 Scala 2.13.2 的金属工作表,当我输入 test.getClass.getCanonicalName 时,我仍然得到向量..

标签: scala vector scala-collections


【解决方案1】:

使用getClass 获取对象的运行时类。其余答案扩展了 Luis 的评论。


Scala 2.13.2 为Vector 引入了implementation subclasses

第二个主要区别在于实现。而老 Vector 对所有支持大小的集合使用单个类,即 新的被分成Vector0Vector6 用于不同的尺寸 的主数据数组。 Vector0 是空的单例对象 向量,Vector1(用于大小不超过 32 的集合)本质上是 和ArraySeq一样,所有更高的维度都是手指树。

/* Contents of Vector.scala in 2.13.2 */

object Vector extends StrictOptimizedSeqFactory[Vector]
sealed abstract class Vector[+A] ...
private sealed abstract class VectorImpl[+A](...) extends Vector[A]
private sealed abstract class BigVector[+A](...) extends VectorImpl[A]
private object Vector0 extends BigVector[Nothing]
private final class Vector1[+A](...) extends VectorImpl[A]
private final class Vector2[+A](...) extends BigVector[A]
private final class Vector3[+A](...) extends BigVector[A]
private final class Vector4[+A](...) extends BigVector[A]
private final class Vector5[+A](...) extends BigVector[A]
private final class Vector6[+A](...) extends BigVector[A]
...

Scala 中不存在的 2.13.1

/* Contents of Vector.scala in 2.13.1 */

object Vector extends StrictOptimizedSeqFactory[Vector]
final class Vector[+A] ...
...

因此Vector(1)在2.13.2中的运行时类是Vector1

Welcome to Scala 2.13.2 (OpenJDK 64-Bit Server VM, Java 1.8.0_202).
Type in expressions for evaluation. Or try :help.

scala> Vector(1).getClass.getCanonicalName
val res0: String = scala.collection.immutable.Vector1

Vector(1) 在 2.13.1 中的运行时类是 Vector

Welcome to Scala 2.13.1 (OpenJDK 64-Bit Server VM, Java 1.8.0_202).
Type in expressions for evaluation. Or try :help.

scala> Vector(1).getClass.getCanonicalName
res0: String = scala.collection.immutable.Vector

从概念上讲,Scala 集合区分 concrete collection type and implementation subclasses

/** Defines the prefix of this object's `toString` representation.
 *
 * It is recommended to return the name of the concrete collection type, but
 * not implementation subclasses. For example, for `ListMap` this method should
 * return `"ListMap"`, not `"Map"` (the supertype) or `"Node"` (an implementation
 * subclass).
 *
 * The default implementation returns "Iterable". It is overridden for the basic
 * collection kinds "Seq", "IndexedSeq", "LinearSeq", "Buffer", "Set", "Map",
 * "SortedSet", "SortedMap" and "View".
 *
 *  @return  a string representation which starts the result of `toString`
 *           applied to this $coll. By default the string prefix is the
 *           simple name of the collection class $coll.
 */
protected[this] def className: String = stringPrefix

例如,我们将Vector1 称为实现子类,而将Vector 称为concrete collection class,尽管Vector 从技术上讲是一个抽象类。

我们也可以观察其他集合类型的实现子类,例如

scala> Set(1).getClass.getCanonicalName
val res1: String = scala.collection.immutable.Set.Set1

实现子类通常是private implementation detail:

您从 Map(...)toMap 获得的具体运行时类是 实施细节和绝大多数时候你不应该 需要担心(但当你这样做时,你可以与getClass联系)。

【讨论】:

    猜你喜欢
    • 2012-05-15
    • 2016-04-25
    • 1970-01-01
    • 1970-01-01
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    • 2011-01-08
    • 1970-01-01
    相关资源
    最近更新 更多