【问题标题】:Parameter type in structural refinement may not refer to an abstract type结构细化中的参数类型可能不引用抽象类型
【发布时间】:2017-05-10 20:58:38
【问题描述】:

以下代码不起作用:

trait A {
  type C

  val Extract: {
    def unapply(c: C): Option[Int] 
  }
}

错误如下:

错误:结构细化中的参数类型可能不引用在该细化之外定义的抽象类型

我想写上面的内容,以便强制特征 A 的用户定义具有 unapply 方法的对象或值,以便我可以在模式匹配中使用它。
感谢"Parameter type in structural refinement may not refer to an abstract type defined outside that refinement"Scala: "Parameter type in structural refinement may not refer to an abstract type defined outside that refinement"(见下文),我找到了两种解决方法,但第一种方法强制继承特征,如果我尝试链接到外部库,这是不可行的;其次,我放弃了覆盖 Extract 以将更多方法放入其中的可能性。

解决方法

trait A {
  type C

  trait Extractable {
    def unapply(c: C): Option[Int]
  }

  val Extract: Extractable
}

trait A {
  type C

  def extract(c: C): Option[Int]

  object Extract {
    def unapply(c: C): Option[Int]  = extract(c)
  }
}

是否有任何方式(可能除了结构类型)可以表达用户可以按照他想要的方式实现Extract 的想法,只要它具有请求签名的方法unapply

【问题讨论】:

    标签: scala


    【解决方案1】:

    你考虑过类型类吗? A 只是声明它的类型参数必须是“可提取的”,也就是说,在范围内必须有一个类型为 Extractable[C] 的隐式值(这只要求您实现 unapply)。这可以来自您、来自其他库或来自用户本人。

    然而,这意味着对于给定类型C,您不能同时拥有多个Extractable[C];也就是说,对于某些给定类型C(例如Int),Extractable 只有一种实现。这与您的用例一致吗?

    trait Extractable[C] {
      def unapply(c: C): Option[Int]
    }
    
    // user can supply his own extractable:
    implicit val myExtractableInt = new Extractable[Int] {
      def unapply(c: Int): Option[Int] = Some(c)
    }
    
    // class A is parameterized by some C 
    // for which Extractable[C] must exist
    class A[C : Extractable] {
      val c: C = ???
      implicitly[Extractable[C]].unapply(c)
    }
    

    编辑:

    要使A 成为特征,我们需要一个(又一个)解决方法:

    trait Extractable[C] {
      def unapply(c: C): Option[Int]
    }
    
    // class A is parameterized by C
    // for which Extractable[C] must exist
    trait A[C] {
      implicit def e: Extractable[C]
      val c: C = ???
      e.unapply(c)
    }
    
    class SomeClass extends A[Int] {
      // we need an implicit Extractable[Int],
      // either from some import or custom one
      implicit def e = new Extractable[Int] {
        def unapply(c: Int): Option[Int] = Some(c)
      }
    }
    

    【讨论】:

    • 是的,这几乎可以工作,但我需要它成为一个特征,因为有几个像A 这样我需要将它们混合在一起。而且特质可能根本没有隐式参数或参数。
    • 编辑后的版本有帮助吗?这仍然是一种解决方法,但我认为您应该对此非常灵活。
    • 您可以使用与问题中相同的名称吗?代替e,写Extract,以便可以在A 的模式匹配中使用它。此外,最好将Extractable trait 放在A 中,这样就不会在A 的子级的其他地方泄露它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-08
    相关资源
    最近更新 更多