【发布时间】:2014-02-05 04:42:42
【问题描述】:
我正在尝试在 Scala 中为 Base64 Variable Length Quanties 编写解码器。
(Base64 VLQ对有符号整数序列进行编码。编码对编码的整数范围没有限制。)
对于我当前的用例,我知道Seq[Int] 就足够了。当然,我想让它解码成Seq[Long],或Seq[BigInteger],甚至是Seq[Short]。
算法完全一样,只是类型不同。
泛型来拯救! (或者我是这么认为的。)
object Base64Vlq {
val continuationMask = (1 << 5).toByte
val signMask = 1.toByte
def decode[T <: Integral[T]](bytes: Seq[Byte]): Seq[T] = {
val result = scala.collection.mutable.ListBuffer[T]()
bytes.foldLeft((0, 0)) { (arg, byte) =>
val (value, n) = arg
if((byte & continuationMask) == 0) {
val newValue = value + (byte / 2 & ~continuationMask) << 5 * n
result += (if((byte & signMask) == 0) { newValue } else { -newValue })
(0, 0)
} else {
(value + (byte & ~continuationMask).toInt << 5 * n, n + 1)
}
}
result
}
}
这有一个编译错误:
error: type mismatch;
found : newValue.type (with underlying type Int)
required: T
result += (if((byte & signMask) == 0) { newValue } else { -newValue })
我可以看到问题:0、value 和 newValue 都是 Int 类型。
我能做些什么来解决这个问题?
仅供参考,这就是我在 C++ 中做同样事情的方式,只需要多几行代码。
#include <vector>
template<typename T>
std::vector<T> decode(std::vector<char> bytes) {
char continuationMask = 1 << 5;
char signMask = 1;
vector<T> result;
int n(0);
T value(0);
for(auto it = bytes.begin(); it != bytes.end(); it++) {
if(*it & continuationMask) {
value += (*it & ~continuationMask) << 5 * n;
n++;
} else {
value += (*it / 2 & ~continuationMask) << 5 * n;
result.push_back(*it & signMask ? -value : value);
value = 0;
n = 0;
}
}
return result;
}
附:附带说明一下,如果有人知道公共 Maven/Ivy 存储库中基于 Java/Scala 的 Base64 VLQ 实现,即使它不是通用的,我会很感激知道它。
【问题讨论】:
-
Scala 中的任何“通用”解决方案都会很慢。您可能会尝试使用专业化来获得更好的性能,但我不确定这会让您走多远。如果您需要速度,而这看起来需要,请保持非泛型。
-
@DanielC.Sobral,是的,Java 泛型很慢。 Alexey 的解决方案,即使有专门化,仍然会影响性能。
标签: scala generics encoding type-conversion