Scala的继承; 生成器故障; 非通用IterableLike(Scala Inherita

2019-10-17 16:38发布

我想实现一个简单的设计目标,但Scala的类型系统的复杂性让我有些头疼。 Traversable的,迭代器,可迭代,流的比较后,查看等我的决定是定义一个自定义特征(我们叫它Stream为简洁起见),其

  • 不通用(我流语义上才有意义,因为有些Stream[StreamEntry]我想避免这样无意义的各类Stream[Int]
  • 也有类似的用法Iterable
  • 像所有成员takedrop等应返回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

这第三个要求要求的模板特征 ,而不是基本特点 (我希望这是标准的术语来指SomeCollectionSomeCollectionLike)的使用。 这意味着我必须使用IterableLike[StreamEntry, Stream]其中重新定义的返回类型的表示集合的一样Iterable延伸IterableLike[A, Iterable[A]]返回Iterable秒。 我的想法是做几乎一样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和非法继承由于在类型参数冲突GenericTraversableTemplateGenInterableTraversable

也许最接近的解决方案是以下几点:

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,因为我从来没有真正想建立一个新的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

现在我觉得有点失去了在斯卡拉型系统的深度。 我仍然是正确的轨道上利用这最后的方针,建造只是缺少一块在这个难题?

而如何将一个Builder实现样子了非一般的非缓存类型? 一个直接的想法来实现+=是使用一些可变的缓冲,但这将是非常反对首先使用迭代器......我应该如何落实to成员,如果我不知道如何构建一个类类型的? 我想所有相关的代码必须在某个地方的图书馆,我只是不能挖掘出来。

Answer 1:

哇! 你有很多事情有...

这里有一些事情你应该知道或解决这个设计问题考虑...

术语:

  • 我们不是指“模板” S,我们称他们为“一般”或“参数”类型。 这样做的原因是,这些类型不是模板 ! 也就是说,他们没有填写他们的实际类型参数来创建新类他们每次使用时(如在C ++中,它正确地使用了“模板”的情况下)。 相反,只有一个类被创建(*),它提供的是泛型类型与特定类型参数的每一个实例。

设计及语言因素:

你说:

......不通用(我流语义上才有意义,因为有些流[StreamEntry]我想避免无意义的类型,如流[INT])

要求主张非通用类。 相反,它是一个什么样的“结合型”是其本质。 例如:

class Generic[T <: UpperBound](ctorArgs...) {
}

在这种情况下,类Generic只能与那些亚型类型的实例化UpperBound 。 (请注意,当我们说“亚型”是指反身亚型的关系。换句话说,每一种类型是本身这个定义下一个亚型。

其结果是:

我不知道你的“流”类或做或已经不是由斯卡拉标准库中现有的类型是否满意? 正如你所发现的扩展标准库的集合类是不完全微不足道,但它肯定是可行的。 我觉得这样做是不是在Scala编程的基本练习,也许不应该试图作为第一个进军斯卡拉之一。

(*)这是足以满足的这种解释的目的过于简单化。



文章来源: Scala Inheritance; Builder Trouble; Non-Generic IterableLike