在scala中展平嵌套元组(没有无形)

时间:2017-01-10 15:20:37

标签: scala generics type-safety

我正在编写一个解码器,用于从字节流解析为具有预定义格式的对象。我想出了下面的课程

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)。

我该怎么办?

1 个答案:

答案 0 :(得分:3)

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