加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

如何确保在map()期间保留自定义Scala集合的动态类型?

发布时间:2020-12-16 10:01:40 所属栏目:安全 来源:网络整理
导读:我读了非常有趣的 article on the architecture of the Scala 2.8 collections,我一直在试验它.首先,我简单地复制了最好的RNA示例的最终代码.这里供参考: abstract class Basecase object A extends Basecase object T extends Basecase object G extends B
我读了非常有趣的 article on the architecture of the Scala 2.8 collections,我一直在试验它.首先,我简单地复制了最好的RNA示例的最终代码.这里供参考:

abstract class Base
case object A extends Base
case object T extends Base
case object G extends Base
case object U extends Base

object Base {
  val fromInt: Int => Base = Array(A,T,G,U)
  val toInt: Base => Int = Map(A -> 0,T -> 1,G -> 2,U -> 3)
}

final class RNA private (val groups: Array[Int],val length: Int)
    extends IndexedSeq[Base] with IndexedSeqLike[Base,RNA] {

  import RNA._

  // Mandatory re-implementation of `newBuilder` in `IndexedSeq`
  override protected[this] def newBuilder: Builder[Base,RNA] =
    RNA.newBuilder

  // Mandatory implementation of `apply` in `IndexedSeq`
  def apply(idx: Int): Base = {
    if (idx < 0 || length <= idx)
      throw new IndexOutOfBoundsException
    Base.fromInt(groups(idx / N) >> (idx % N * S) & M)
  }

  // Optional re-implementation of foreach,// to make it more efficient.
  override def foreach[U](f: Base => U): Unit = {
    var i = 0
    var b = 0
    while (i < length) {
      b = if (i % N == 0) groups(i / N) else b >>> S
      f(Base.fromInt(b & M))
      i += 1
    }
  }
}

object RNA {

  private val S = 2 // number of bits in group
  private val M = (1 << S) - 1 // bitmask to isolate a group
  private val N = 32 / S // number of groups in an Int

  def fromSeq(buf: Seq[Base]): RNA = {
    val groups = new Array[Int]((buf.length + N - 1) / N)
    for (i <- 0 until buf.length)
      groups(i / N) |= Base.toInt(buf(i)) << (i % N * S)
    new RNA(groups,buf.length)
  }

  def apply(bases: Base*) = fromSeq(bases)

  def newBuilder: Builder[Base,RNA] =
    new ArrayBuffer mapResult fromSeq

  implicit def canBuildFrom: CanBuildFrom[RNA,Base,RNA] =
    new CanBuildFrom[RNA,RNA] {
      def apply(): Builder[Base,RNA] = newBuilder
      def apply(from: RNA): Builder[Base,RNA] = newBuilder
    }
}

现在,这是我的问题.如果我运行这个,一切都很好:

val rna = RNA(A,U)
println(rna.map(e => e)) // prints RNA(A,U)

但是这段代码将RNA转换为Vector!

val rna: IndexedSeq[Base] = RNA(A,U)
println(rna.map(e => e)) // prints Vector(A,U)

这是一个问题,因为不知道RNA类的客户端代码可能会在仅从Base映射到Base时将其转换回Vector.为什么会这样,有什么方法可以解决它?

P.-S.:我找到了一个试探性的答案(见下文),如果我错了,请纠正我.

解决方法

如果rna变量的静态类型是IndexedSeq [Base],则自动插入的CanBuildFrom不能是RNA伴随对象中定义的那个,因为编译器不应该知道rna是RNA的实例.

那么它来自哪里?编译器依赖于GenericCanBuildFrom的实例,该实例是IndexedSeq对象中定义的实例. GenericCanBuildFroms通过在原始集合上调用genericBuilder [B]来生成它们的构建器,并且该泛型构建器的要求是它可以生成可以包含任何类型B的泛型集合 – 当然,传递给映射的函数的返回类型()不受约束.

在这种情况下,RNA只是一个IndexedSeq [Base]而不是一般的IndexedSeq,因此不可能在RNA中覆盖genericBuilder [B]以返回特定于RNA的构建器 – 我们必须在运行时检查B是否为Base或别的什么,但我们做不到.

我认为这解释了为什么,在这个问题上,我们得到了一个Vector.至于我们如何解决它,这是一个悬而未决的问题……

编辑:修复此问题需要map()知道它是否映射到A的子类型.为此,需要对集合库进行重大更改.请参阅相关问题Should Scala’s map() behave differently when mapping to the same type?.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读