在 Scala 中,Inner case class 如何始终覆盖方法?

In Scala, how can an Inner case class consistently override a method?

我最近发现 Scala 编译器对案例 class 有一个有趣的特性:因为它生成一个 class 和一个对象签名,如果定义为内部 class,它可以用最少的样板代码覆盖抽象类型定义和它的超级class的函数定义,这里是一个例子:

object InnerCaseClassOverridingBoth {

  trait AALike

  trait SS {
    type AA <: AALike
    def AA(): AnyRef
  }

  trait SS_Clear extends SS {
    def AA(): AnyRef
  }

  class SSA extends SS_Clear {
    case class AA() extends AALike
  }
  object SSA extends SSA {}
}

这将编译而不会出现任何错误。然而,快捷方式到此为止,如果函数定义 def AA 被参数化,那么内部 case class 和内部对象都无法覆盖它:内部对象的 apply 函数不能t 自动扩展到其外部的方法 class:

  trait SS_Parameterised extends SS {
    def AA(ii: Int): AnyRef
  }

  class SSB extends SS_Parameterised {
    case class AA(ii: Int) extends AALike
  }
  object SSB extends SSB {}

这给出了一个错误:

class SSB needs to be abstract, since method AA in trait
SS_Parameterised of type (ii: Int)AnyRef is not defined
    class SSB extends SS_Parameterised {

我的问题是,这种情况下有捷径吗?为什么 Scala 编译器设计为 link 情况 1 而不是情况 2?

它根本不是特别设计的;或者,它是,但不是你想的那样。您不是用构造 AA 的方法覆盖 def AA(),而是用 object AA 本身覆盖它。注意事项

trait T {
   type I <: AnyRef
   def I(): AnyRef
}
object O extends T {
   case class I(val i: Int)
}

这很好用。

> (O: T).I()
I
> (O: T).I().getClass
class O$I$
> O.I(5)
I(5)
> O.I(5).getClass
class O$I

突出的设计选择是“objects 可以覆盖无参数 defs”(vals、vars 也可以,当然, 无参数 defs) 和“case classes 自动生成 objects”。 "Inner case classes override methods of the same name in their outer class with their constructors," 不是 Scala 的规则之一。 object O包含一个case class I和一个object I,摘要def I(): AnyRef被覆盖为return表示object Iobject I的内容无所谓,因为def I()只需要return和AnyRef,也就是说没有任何限制。完全有道理

trait U {
   type I <: AnyRef
   def I(i: Int): AnyRef
}
object P extends U {
   case class I(i: Int)
}

那么失败。 object P 包含一个 case class I 和一个关联的 object I,但它还需要一个 def I(i: Int): AnyRef,而它缺少。

我猜这只是与 apply 在案例 类 中扮演的角色有关。参见 Case Class default apply method SSA 通过 SSA (SSA.apply) 的伴随对象满足 SS_Clear.AA

当您向方法添加参数时,您不再有 0 参数 apply 方法来履行该角色。

好的,我找到了 2 种方法

方法 1:被大小写覆盖 class:

  trait SS_Parameterised {
    type AA <: AALike
    def AA: Int => AnyRef
  }

方法 2:被隐式覆盖 class:

  trait SS_Parameterised {
    type AA <: AALike
    implicit def AA(ii: Int): AnyRef
  }

  class SSB extends SS_Parameterised {
    implicit class AA(ii: Int) extends AALike
  }

故事结束 :) 一个案例 class 覆盖了 2 个声明?没问题。

(方法 2 的工作原理是 scala 在内部为每个隐式 class 生成一个隐式函数)