我正在尝试为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;
}
P.S。作为旁注,如果有人知道公共Maven / Ivy回购中基于Java / Scala的Base64 VLQ实现,即使它不是通用的,我也很高兴知道它。
答案 0 :(得分:6)
绑定T <: Integral[T]
说T
必须是Integral[T]
的子类型,这是错误的;你需要一个上下文绑定 T: Integral
或者(对于这种情况更好)一个隐式参数(实际上,一个上下文绑定编译成一个隐式参数,唯一的区别是你不能给这是一个名字)。
像这样的东西(未经测试,只是检查它是否编译):
object Base64Vlq {
val continuationMask = (1 << 5).toByte
val signMask = 1.toByte
def decode[T](bytes: Seq[Byte])(implicit ev: Integral[T]): Seq[T] = {
val result = scala.collection.mutable.ListBuffer[T]()
val tZero = ev.zero
bytes.foldLeft((tZero, 0)) { (arg, byte) =>
val (value, n) = arg
if((byte & continuationMask) == 0) {
val newValue = ev.plus(value, ev.fromInt((byte / 2 & ~continuationMask) << 5 * n))
result += (if((byte & signMask) == 0) { newValue } else { ev.negate(newValue) })
(tZero, 0)
} else {
(ev.plus(value, ev.fromInt((byte & ~continuationMask).toInt << 5 * n)), n + 1)
}
}
result
}
}
要使用,您必须说明您想要的类型:
编辑:我没有在您的C ++代码n
中看到T
,并认为它是Int
。
评论的答案:
这就像Integral
这样的类型有效:它们是Scala的type classes版本。如果要在现有类型上引入新操作,显然无法向它们添加新的超类型,因此会创建Integral[Int]
,Integral[BigInt]
等隐式实例。
编译器不知道T
使用什么类型,您需要告诉它:例如: Base64Vlq.decode[Int](Seq[Byte]())
或Base64Vlq.decode[BigInt](Seq[Byte]())
。
答案 1 :(得分:2)
这并不能解决您的问题,但希望它可以帮助您编写通用解决方案。请查看Integral和IntegralOps提供的操作。问题在于位操作。如果选择这种方式,则必须使用Integral和IntegralOps支持的操作重写它们。祝你好运。
object Base64Vlq {
val continuationMask = (1 << 5).toByte
val signMask = 1.toByte
def decode[T](bytes: Seq[Byte])(implicit integral: Integral[T]): Seq[T] = {
import integral._
val result = scala.collection.mutable.ListBuffer[T]()
bytes.foldLeft((integral.zero, integral.zero)) { (arg, byte) =>
val (value, n) = arg
if((byte & continuationMask) == integral.zero) {
// Just a meaningless example calculation:
result += integral.fromInt(2) + (value * n)
(integral.zero, integral.zero)
} else {
// Just a meaningless example calculation:
(value + integral.fromInt(3) * n, n + integral.fromInt(1))
}
}
result
}
}