如何在构造函数中实现参数和路径相关的类型参数化?

How to achieve argument and path dependent type parametrization in constructor?

(使用 scala 2.11.12)

为什么编译?

  sealed trait Inner

  sealed trait Outer {
    sealed trait I extends Inner
  }

  case object OuterA extends Outer {
    case object Inner1 extends I
    case object Inner2 extends I
  }

  case object OuterB extends Outer {
    case object Inner1 extends I
  }

  class Data[O <: Outer](outer: O, inner: O#I)
  // I expected this not to compile but it actually does
  val data = new Data(OuterA, OuterB.Inner1)

为什么不能编译?

  sealed trait Inner

  sealed trait Outer {
    type I <: Inner
  }

  case object OuterA extends Outer {
    sealed trait OuterAInner extends Inner
    override type I = OuterAInner
    case object Inner1 extends OuterAInner
    case object Inner2 extends OuterAInner
  }

  case object OuterB extends Outer {
    sealed trait OuterBInner extends Inner
    override type I = OuterBInner
    case object Inner1 extends OuterBInner
  }

  class Data[O <: Outer](outer: O, inner: O#I)
  // I expected this to compile but it actually does not
  val data = new Data(OuterA, OuterA.Inner1)
  // type mismatch;
  //   found   : com.transparencyrights.ermine.model.V1.OuterA.Inner1.type
  //   required: ?#I
  //  Note that Inner1 extends Any, not AnyRef.
  //  Such types can participate in value classes, but instances
  //  cannot appear in singleton types or in reference comparisons.
  //    val data = new Data(OuterA, OuterA.Inner1)

我想要实现的是一个独特的 Data 构造函数,它接受两个参数,一个 Outer 和一个 InnerInner 类型限制为 Inner 子类型依赖于给定的 Outer 实例。

在这两种情况下,问题是 O#I 没有按照您的意愿去做。
它实际上不是指您拥有的特定 O 内的 I,而是指 Outer.

内的通用

您可以使用路径相关类型广义类型约束

修复这两个片段

案例一

sealed trait Inner

sealed trait Outer {
  sealed trait I extends Inner
}

final case object OuterA extends Outer {
  final case object Inner1 extends I
  final case object Inner2 extends I
}

final case object OuterB extends Outer {
  final case object Inner1 extends I
}

final class Data[O <: Outer, I <: O#I] private (outer: O, inner: I)

object Data {
  final def apply[O <: Outer, I <: O#I](outer: O, inner: I)(implicit ev: I <:< outer.I): Data[O, I] =
    new Data(outer, inner)
}

val data = Data(OuterA, OuterB.Inner1) // Does not compile.
val data = Data(OuterA, OuterA.Inner1) // Does compile.

案例二

sealed trait Inner

sealed trait Outer {
  type I <: Inner
}

final case object OuterA extends Outer {
  override final type I = OuterAInner

  sealed trait OuterAInner extends Inner

  final case object Inner1 extends OuterAInner
  final case object Inner2 extends OuterAInner
}

final case object OuterB extends Outer {
  override final type I = OuterBInner

  sealed trait OuterBInner extends Inner

  final case object Inner1 extends OuterBInner
}

final class Data[O <: Outer, I <: O#I] private (outer: O, inner: I)

object Data {
  final def apply[O <: Outer, I <: O#I](outer: O, inner: I)(implicit ev: I <:< outer.I): Data[O, I] =
    new Data(outer, inner)
}

val data = new Data(OuterA, OuterA.Inner1) // Does compile.
val data = new Data(OuterA, OuterB.Inner1) // Does not compile.

现在,由于示例没有显示您想如何使用 Data class 和 outer & 个字段,这可能还不够,希望对你有帮助。
如果您有任何疑问,请随时在评论中提问。