Dotty提供什么来取代类型投影?

时间:2018-04-26 12:58:53

标签: scala dotty type-projection

我一直在阅读有关Dotty的内容,因为看起来它似乎将成为scala 3,并注意到类型预测被视为“不健全”并从语言中移除......

这看起来很糟糕,因为我看到了几个非常有用的用例。例如:

trait Contents
class Foo extends Contents
class Bar extends Contents

trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]

trait Manager[T <: Container[_]] { 
  type ContainerType = T 
  type ContentType = T#ContentType
  def getContents: ContentType 
  def createContainer(contents: ContentType): ContainerType
}

如何在Dotty中做这样的事情?将第二个类型参数添加到Manager?但是,除了它使创建和操作Manager的实例变得非常繁琐之外,它也不太有用,因为没有办法强制执行这两种类型之间的关系({{1不应该是合法的。)

然后,还有其他用途,比如类型lambda和部分应用类型,它们对于创建有偏见的仿函数等很有用......或者这些(部分应用的类型)在Dotty中成为“一等公民”?

编辑

要回答评论中的问题,这里有一个有点人为的例子,可以使用他的这个。我们假设,我的Manager[FooContainer, Bar]实际上是Akka Managers

Actors

1 个答案:

答案 0 :(得分:0)

在Scala 2.12中,类型投影有时可以替换为类型类+依赖于路径的类型

trait ContentType[T <: Container[_]] {
  type Out
}
object ContentType {
  type Aux[T <: Container[_], Out0] = ContentType[T] { type Out = Out0 }
  def instance[T <: Container[_], Out0]: Aux[T, Out0] = new ContentType[T] { type Out = Out0 }

  implicit def mk[T <: Contents]: Aux[Container[T], T] = instance
}

abstract class Manager[T <: Container[_]](implicit val contentType: ContentType[T]) {
  type ContainerType = T
  def getContents: contentType.Out
  def createContainer(contents: contentType.Out): ContainerType
}

在Dotty 0.16.0-bin-20190529-3361d44-NIGHTLY中检入

trait Contents
class Foo extends Contents
class Bar extends Contents

trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]

trait ContentType[T <: Container[_]] {
  type Out
}
object ContentType {
  implied [T <: Contents] for ContentType[Container[T]] {
    type Out = T
  }
}

trait Manager[T <: Container[_]] given (val contentType: ContentType[T]) {
  type ContainerType = T
  type ContentType = contentType.Out
  def getContents: ContentType
  def createContainer(contents: ContentType): ContainerType
}

另一种选择是使用match types

trait Contents
class Foo extends Contents
class Bar extends Contents

trait Container[T <: Contents] { type ContentType = T }
class FooContainer extends Container[Foo]
class BarContainer extends Container[Bar]

type ContentType[T <: Container[_]] = T match {
  case Container[t] => t
}

trait Manager[T <: Container[_]] {
  type ContainerType = T
  def getContents: ContentType[T]
  def createContainer(contents: ContentType[T]): ContainerType
}