依赖类型的隐式扩展

Implicit expansion with dependant types

我想知道为什么以下情况不起作用。假设我有两种类型:

trait Def[T]
trait Ref[T]
case class Module()

我想将 Def 转换为 Ref,因此我声明了以下方法:

object Ref {
  implicit def fromDef[A](defin: Def[A])(implicit rc: RefConverter[A]): Ref[rc.ResType] = new Ref[rc.ResType] {}
}

但万一:

val moduleDef: Def[Module] = ???
val moduleRef: Ref[Module] = moduleDef

Scala 编译器无法找到正确的转换方式(即 fromDef 函数),但如果我们明确告诉它使用此转换,即 Ref.fromDef(moduleDef),scalac 会找到正确的RefConverter 实例。另一个需要考虑的重要事项是,如果我将结果类型更改为 Ref[A],它也会解析转换链。所以编译器无法解析具有依赖结果类型的链?

编译如下:

trait Def[T]
trait Ref[T]
case class Module()

trait RefConverter[T]{
  type ResType = T
  type RefType = T
}
object Ref {
  implicit def fromDef[A](defin: Def[A])(implicit rc: RefConverter[A]): Ref[rc.ResType] = new Ref[rc.RefType] {}
}
implicit val rc = new RefConverter[Module]{}
val d = new Def[Module]{}
val r = d:Ref[Module]

这会编译并打印类型:

object Test extends App {

  implicit val rc = new RefConverter[Module] {}

  object Ref {
    implicit def fromDef[A](defin: Def[A])(implicit rc: RefConverter[A]): Ref[rc.ResType] = new Ref[rc.ResType] {}
  }

  val moduleDef: Def[Module] = new Def[Module]() {}
  val moduleRef: Ref[Module] = moduleDef

  println(moduleDef.getClass.getName)
  println(moduleRef.getClass.getName)

  trait RefConverter[T] {
    type ResType = T
  }

  trait Def[T]

  trait Ref[T]

  case class Module()
}

我假设您的 Refconverter 不在范围内,或者您被我们的 IDE 强调为错误而误导了。

您必须将类型参数和类型成员绑定在一起。

您可以像其他答案一样提供别名;请注意,它不适用于特征中绑定的类型,请参阅代码注释。

但是你可以提供另一个有界的类型参数:

trait Ref[T]
trait Def[T]
case class Module()

object Ref {
  //implicit def fromDef[A](defin: Def[A])(implicit rr: RefResolver[A]): Ref[rr.RefType] = new Ref[rr.RefType] {}
  //implicit def fromDef[A](defin: Def[A])(implicit rr: RefResolver[A]): Ref[A] = new Ref[A] {}  // OP notes that this works
  implicit def fromDef[A, B <: A](defin: Def[A])(implicit rr: RefResolver[B]): Ref[B] = new Ref[B] {}
  // or
  implicit def fromDef[A](defin: Def[A])(implicit rr: RefResolver[A]): Ref[A] { type RefType <: A } = new Ref[A] { type RefType = A }
}

trait RefResolver[A] {
  type RefType
  //type RefType <: A    // not good enough
}

object RefResolver {
  implicit val moduleRes: RefResolver[Module] { type RefType = Module } =
    new RefResolver[Module] {
      type RefType = Module
    }
}

object Test extends App {
  val moduleDef: Def[Module] = new Def[Module] {}
  val moduleRef: Ref[Module] = moduleDef
}