【发布时间】:2013-01-26 17:04:02
【问题描述】:
我试图实现一个简单的设计目标,但是 Scala 类型系统的复杂性让我有些头疼。在比较了 Traversable、Iterator、Iterable、Stream、View 等之后,我决定定义一个自定义 trait(为了简洁起见,我们称之为 Stream)
- 是非泛型的(我的流在语义上只对
Stream[StreamEntry]有意义,我想避免像Stream[Int]这样无意义的类型) - 与
Iterable的用法相似 -
take、drop等所有成员都应返回Stream,而不是基本的Iterable。
这是我迄今为止尝试过的:
方法 1
为了勾勒用例,一个简单的例子(违反了第三个设计目标)是:
case class StreamEntry(data: Double) // just a dummy
trait Stream extends Iterable[StreamEntry] {
val metaInfo: String
}
// example use case
val s = new Stream {
val metaInfo = "something"
val iterator = StreamEntry(1) :: StreamEntry(2) :: StreamEntry(3) :: Nil toIterator
}
val t = s.take(1) // unfortunately, this is no longer a Stream
方法2
这第三个要求要求使用 template trait 而不是 base trait(我希望这是引用 SomeCollection 或 SomeCollectionLike)。这意味着我必须使用IterableLike[StreamEntry, Stream] 重新定义表示集合的返回类型,就像Iterable 扩展IterableLike[A, Iterable[A]] 以返回Iterables。我的想法是和Iterable 做的差不多。这将是:
// this is exactly the way `Iterable` is defined, but non-generic
trait Stream extends Traversable[StreamEntry]
with GenIterable[StreamEntry]
with GenericTraversableTemplate[StreamEntry, Stream]
with IterableLike[StreamEntry, Stream] {
...
}
不幸的是,这无法编译,因为Stream 显示为GenericTraversableTemplate 的模板参数,而编译器现在需要Stream 本身的模板参数(正好是一个),这是有道理的。
方法 3、4、...
从这里开始,我迷失在类型系统中。仅删除with GenericTraversableTemplate 会导致newBuilder 的类型不兼容,并且由于GenericTraversableTemplate 中的类型参数与GenInterable 和Traversable 的冲突而导致非法继承。
也许最接近的解决方案如下:
trait Stream extends TraversableLike[StreamEntry, Stream]
with IterableLike[StreamEntry, Stream] {
val metaInfo: String
def seq = this
def newBuilder: scala.collection.mutable.Builder[StreamEntry, Stream] = ???
}
这可以编译,但不幸的是我不知道如何实现 Builder。是否可以为我的非通用特征重用通用生成器?实际上,我虽然可以不使用 Builder,因为我真的不想从其他集合中构建新的 Stream。但是目前我在使用这种方法时遇到了一些奇怪的运行时行为,我无法完全理解。例如:
val s = new Stream {
val metaInfo = "something"
val iterator = StreamEntry(1) :: StreamEntry(2) :: StreamEntry(3) :: Nil toIterator
}
// executing the following independently (not in sequence) results in:
s.take(1) // throws: scala.NotImplementedError: an implementation is missing
// seems to require a Builder :(
s.toArray // works
s.toIterator // works
s.toIterable // throws: java.lang.ClassCastException: cannot be cast to scala.collection.Iterable
现在我对 Scala 类型系统的深度感到有些迷茫。我是否仍然在使用最后一种方法的正确轨道上,而 Builder 是否只是这个难题中缺失的部分?
对于非泛型非缓存类型,Builder 实现会是什么样子?实现+= 的一个简单想法是使用一些可变缓冲区,但这首先会非常反对使用迭代器......如果我不知道如何实现to 成员构造一个那种类型的类?我想所有相关的代码一定在图书馆的某个地方,我就是挖不出来。
【问题讨论】:
-
您应该知道
Stream是一个内置类型,因此不应在您自己的代码中重新定义该名称。它会让那些更熟悉 Scala 标准库的人感到困惑。 -
我知道并且我正在考虑将其重命名为
MyStream以发布此帖子,但我同样清楚地提到我将在下面将我的自定义特征称为Stream。跨度> -
你应该看看标准库中StringOps和WrappedString的实现。
-
@Ptharien'sFlame:我确实对此进行了调查,但如果我在这些情况下使用类似于底层构建器的构建器(一个高度可变的 Java StringBuilder),我最终会得到我没有的想要:调用例如'drop'会将整个流的其余部分存储在内存中。我现在的感觉是,这只能通过非基于构建器的集合来解决,这意味着 Iterable 不是要走的路。
标签: scala inheritance iterator builder