【发布时间】:2016-05-18 21:48:29
【问题描述】:
背景
我正在使用 Akka Streams,我想向 Flow[In, Out, Mat] 添加一些扩展方法,这些方法专门用于 Out 是 Seq 时。
我从这个 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