如何将类型投影转换为隐式的PDT?

问题描述

这是一个惯用的scala 2示例:

trait Box {
    type Content
    val content :Content
}

implicit class BoxExtension[B <: Box](private val self :B) extends AnyVal {
    def map[O](f :self.Content => O)(implicit mapper :Mapper[B,O]) :mapper.Res =
        mapper(self)(f)
}


trait Mapper[B <: Box,O] {
    type Res
    def apply(box :B)(f :box.Content => O) :Res
}

如您所见,它已经部分转换为依赖于路径的类型。但是,如何为引用了Mapper的{​​{1}}类型(例如O本身)创建self.Content的隐式值呢?理想情况下,在Scala 2和Scala 3之间具有直接等效的解决方案。

解决方法

您可以为此进行隐式定义。由于Dotty不允许在抽象类型上进行类型投影,因此需要一个额外的类型参数。另外,我不得不公开self,因为它被用于map的签名中。

object Mapper {
  implicit def uselessMapper[B <: Box{type Content = C},C]: Mapper[B,C] { type Res = AllPurposeBox[C] } =
    new Mapper[B,C] {
      type Res = AllPurposeBox[C]
      def apply(box: B)(f: box.Content => C) =
        new AllPurposeBox(f(box.content))
    }
}

class AllPurposeBox[T](override val content: T) extends Box {
  type Content = T
}

Full example

我通常建议改为将类型参数用于Box和{(对于Mapper使用附加参数),但是它会得到little complicated。也许您可以将BoxExtension转换成this之类的东西,并以C作为额外参数:

implicit class BoxExtension[B <: Box {type Content = C},C](private val self: B) extends AnyVal {
  def map[O](f: C => O)(implicit mapper: Mapper[B,O]): mapper.Res =
    mapper(self)(f)
}

如果您愿意只使用Dotty而不是交叉编译,则可以进行this

trait Mapper[B <: Box,O] {
  type Res
  def apply(box: B)(f: box.Content => O): Res
  extension (self: B) def map(f: self.Content => O): Res = apply(self)(f)
}
object Mapper {
  given uselessMapper[B <: Box{type Content = C},C] as Mapper[B,C] {
    type Res = AllPurposeBox[C]
    def apply(box: B)(f: box.Content => C) = new AllPurposeBox(f(box.content))
  }
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...