我讀了非常有趣的article on the architecture of the Scala 2.8 collections,我一直在嘗試一下。首先,我簡單地複製了最好的代碼RNA
的例子。這裏僅供參考:如何確保我的自定義Scala集合的動態類型在映射()期間保留?
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, Base, RNA] {
def apply(): Builder[Base, RNA] = newBuilder
def apply(from: RNA): Builder[Base, RNA] = newBuilder
}
}
現在,這是我的問題。如果我運行這個,一切都很好:
val rna = RNA(A, G, T, U)
println(rna.map(e => e)) // prints RNA(A, G, T, U)
但這個代碼將RNA轉換爲Vector!
val rna: IndexedSeq[Base] = RNA(A, G, T, U)
println(rna.map(e => e)) // prints Vector(A, G, T, U)
這是一個問題,因爲客戶機代碼不知道RNA
類的可以轉換回一個Vector
代替當僅映射從Base
到Base
。爲什麼會這樣,以及有什麼方法來解決它?
P.-S .:我找到了一個試探性的答案(見下文),如果我錯了,請糾正我。
這可能是一個愚蠢的想法,但是......你爲什麼,因爲它在IndexedSeq做不覆蓋的伴侶? – CheatEx 2011-04-14 09:40:57
'companion'必須返回'GenericCompanion [IndexedSeq]'。如果'RNA'對象實現它,那麼它必須定義'def newBuilder:Builder [A,IndexedSeq [A]]',它比我們想提供的構建器更普遍,所以我們不能這樣做。 – 2011-04-14 11:56:08
類似於http://stackoverflow.com/questions/4563484/different-behavior-when-declaration-type-is-differentset-vs-treeset/4564811#4564811。我也認爲客戶端代碼顯式輸入到'IndexedSeq [Base]'並不是一個好主意,但是卻期望RNA行爲。爲什麼不做'val rna = RNA(A,G,T,U)'? – huynhjl 2011-04-14 12:03:37