1
我正在写一个解码器从字节流解析到预定义格式的对象。我想出了下面类在斯卡拉flatten嵌套元组(无形)
trait Decoder[In] {
type Out
def decode(bs: In): (Out, In)
}
object Decoder {
type ByteString = List[Byte] // for testing...
// define some blocks for client to chain up to build format pattern
val int = new Decoder[ByteString] {
type Out = Int
def decode(bs: ByteString): (Out, ByteString) = {
val (fst, snd) = bs.splitAt(4)
val value = fst.foldLeft(0)((acc, b) => acc * 0xff + b)
(value, snd)
}
}
val long = new Decoder[ByteString] {
type Out = Long
def decode(bs: ByteString): (Out, ByteString) = {
val (fst, snd) = bs.splitAt(8)
val value = fst.foldLeft(0L)((acc, b) => acc * 0xff + b)
(value, snd)
}
}
}
然后创建一个辅助生成器来手拉葫芦起来:
class DecoderBuilder[In](decoder: Decoder[In]) {
def ~(d: Decoder[In]) = {
val combine = new Decoder[In] {
type Out = (decoder.Out, d.Out)
def decode(bs: In): (Out, In) = {
val (el1, remain1) = decoder.decode(bs)
val (el2, remain2) = d.decode(remain1)
((el1, el2), remain2)
}
}
new DecoderBuilder(combine)
}
def buildApply[T](data: In)(f: decoder.Out => T) = f(decoder.decode(data)._1)
}
object DecoderBuilder {
implicit def ddd[In](d: Decoder[In]) = new DecoderBuilder(d)
}
有了上面的代码,我已经可以写出像这样的代码:
import Decoder._
import DecoderBuilder._
val data = List[Byte](
0x00, 0x00, 0x00, 0x01, // the 1st field: Int
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // 2nd field: Long
0x00, 0x00, 0x00, 0x03 // the 3rt field: Int
)
val format_type = int ~ long ~ int
val result_type = format_type.buildApply(data) {
case ((i, l), ii) => MyObject(i, l, ii)
}
println(result_type) // --> MyObject(1,2,3)
然而,当格式变长时,嵌套元组变得难以阅读。无论如何重写DecoderBuilder
以上,以便客户端(与buildApply
)可以使用拼合元组来代替?我知道无定形可以很容易地做到这一点,但我不想为此添加额外的库。
P/S: 现在的代码仔细寻找一遍,我意识到,它不能推断出类型里面buildApply
,即我不能做到这一点
val result_type = format_type.buildApply(data) {
a => MyObject(a._1._1, a._1._2, a.2)
}
因为a
类型format_typedecoder.Out
,不`((Int,Long),Int)。
我该怎么做才能做到这一点?
我意识到我们可以通过HList折叠,真是太棒了!所以我想我会编码像'int :: long :: int :: HNil'这样的格式,然后使用另一个HList作为累加器来取回'1 :: 2 :: 3 :: HNil'。但看着无形回购的折叠例子,我仍然不知道如何去做,或者根本不可能。你能给我一些提示吗?再次感谢你这样有用的图书馆:) – it4rb