2017-01-10 25 views
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)。

我该怎么做才能做到这一点?

回答

3

不成形是下一个许可证发布,Apache 2.0的,没有什么可以阻止你简单地复制和相关类型类和实例粘贴到您的项目。你不会做得更好,而且非常欢迎你这样做。

+0

我意识到我们可以通过HList折叠,真是太棒了!所以我想我会编码像'int :: long :: int :: HNil'这样的格式,然后使用另一个HList作为累加器来取回'1 :: 2 :: 3 :: HNil'。但看着无形回购的折叠例子,我仍然不知道如何去做,或者根本不可能。你能给我一些提示吗?再次感谢你这样有用的图书馆:) – it4rb