【问题标题】:How to call a generic method with a runtime type parameter in Scala?如何在 Scala 中调用具有运行时类型参数的泛型方法?
【发布时间】:2016-05-18 21:48:29
【问题描述】:

背景

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

我从这个 trait 开始,以便于获取类型字段:

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?如果是这样,我该怎么做?

【问题讨论】:

    标签: scala generics reflection akka-stream


    【解决方案1】:

    您不能通过以下方式之一定义隐式类来访问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] {}
    

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

    【讨论】:

    • 我实际上还没有机会尝试这个,但我很确定第一个是我已经尝试过的。它导致隐式转换失败。我想知道我是否在某处错过了类型参数。似乎应该有足够的信息让编译器知道如何去做。我认为第二个选项行不通,因为Out 不再是Seq
    • 因为我不使用 Akka Streams,所以我在一个稍微简单的版本中都尝试过,但它们在基本的 REPL 会话中工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多