【问题标题】:How to achieve argument and path dependent type parametrization in constructor?如何在构造函数中实现参数和路径依赖类型参数化?
【发布时间】:2019-12-11 02:11:48
【问题描述】:

(使用 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 和一个Inner,其中Inner 类型限制为Inner 子类型取决于给定的Outer实例。

【问题讨论】:

    标签: scala generics inner-classes path-dependent-type


    【解决方案1】:

    在这两种情况下,问题是O#I 没有做你想做的事。
    它实际上并不是指您拥有的特定O 中的I,而是指Outer 中的通用@。

    您可以使用路径依赖类型通用类型约束修复 sn-ps。

    案例一

    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.
    

    案例 2

    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 类和 outerinner 字段,这可能还不够,希望对您有所帮助。
    如果您有任何疑问,请随时向 cmets 提问。

    【讨论】:

    • 实际上它在两种情况下都可以在没有通用类型约束(implicit ev: I &lt;:&lt; outer.I) 的情况下工作(在 Scastie 中使用 scala 2.11、2.12 和 2.13 进行了测试)。第二个泛型类型参数I &lt;: O#I 就足够了。看起来O#I 在泛型类型参数绑定的上下文中的行为与用作参数类型时的行为不同,您对此有什么提示吗?
    • @M.Karassev 嗯,抱歉,没有。你也可以使用两个参数列表,比如final def apply[O &lt;: Outer](outer: O)(inner: outer.I)
    • 这会按照 cmets 中的说明进行编译,还是我遗漏了什么? scastie.scala-lang.org/veLlWOvgTSOTd6wLaPty8w
    • @M.Karassev 在这种情况下,您似乎甚至不需要 Data 的伴随对象:scastie.scala-lang.org/BalmungSan/Iw0K2xrdQoWjcKVNwy9i8Q/2 - 但正如我所说,诀窍在于如何你想使用所有这些东西吗?
    猜你喜欢
    • 2021-03-22
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 2011-10-24
    相关资源
    最近更新 更多