如何在Scala中使用运行时类型参数调用泛型方法?

时间:2016-05-18 21:48:29

标签: scala generics reflection akka-stream

背景

我正在使用Akka Streams,我想向Flow[In, Out, Mat]添加一些扩展方法,这些方法专门用于OutSeq时。

我从这个特性开始,以便轻松获得类型字段:

trait StageOps[+Out, +Mat] {
  protected val stage: FlowOps[Out, Mat]
  type Repr[+O] = stage.Repr[O]
  type Closed = stage.Closed
}

然后我有了这个(后面会详细介绍):

trait FramingOps[Out <: Seq[_], Mat] extends StageOps[Out, Mat] {
  def frame(start: Out, end: Out): Repr[Out] = {
    ...
  }
}

现在是隐式转换:

implicit class SeqFlowOps[In, Out <: Seq[_], Mat](val stage: Flow[In, Out, Mat])
  extends FramingOps[Out, Mat] {}

这很有效,我可以做类似的事情:

val byteFlow: Flow[ByteString, ByteString, _] = ??? // Some flow from somewhere else
byteFlow.frame(ByteString(0x0B), ByteString(0x1C, 0x0D)) // Implicit conversion

问题

FramingOps#frame的实施已经发展到我需要做的事情:

def frame(start: Out, end: Out): Repr[Out] = {
  val maxBufferSize = math.max(start.length, end.length) - 1
  val checkForMalformedChunk = stage.statefulMapConcat[Out](() => {
    var buffer = Seq.empty[Any]
    (chunk: Out) => {
      buffer = buffer ++ chunk
      if (buffer.containsSlice(start) || buffer.containsSlice(end)) ??? // Bad encoding!
      buffer = buffer.takeRight(maxBufferSize)
      immutable.Seq(chunk)
    }
  })
  checkForMalformedChunk.prepend(Source.single(start)).concat(Source.single(end))
}

现在不得不使用var buffer = Seq.empty[Any],但我相信我能做得更好。

由于无法提供元素类型,此尝试会中断隐式转换:

trait FramingOps[Elem, Out <: Seq[Elem], Mat] extends StageOps[Out, Mat] { ... }

所以我认为使用TypeTag可能是唯一的选择:

abstract class FramingOps[Out <: Seq[_] : TypeTag, Mat] extends StageOps[Out, Mat] { ... }

现在我可以使用以下命令在运行时获取元素类型:

implicitly[TypeTag[Out]] match { case TypeRef(_, _, List(elemType)) => elemType }

但是如何使用它来创建正确类型的空序列?我是否需要继续使用反射并提供类型参数myslef?如果是这样,我该怎么做?

1 个答案:

答案 0 :(得分:0)

您无法通过以下方式之一定义隐式类来访问Elem类型吗?

implicit class SeqFlowOps[In, Out[X] <: Seq[X], Mat, Elem](val stage: Flow[In, Out[Elem], Mat])
  extends FramingOps[Elem, Out[Elem], Mat] {}

implicit class SeqFlowOps[In, Out, Mat, Elem](val stage: Flow[In, Out with Seq[Elem], Mat])
  extends FramingOps[Elem, Out, Mat] {}

我还没有彻底测试过这个...