В Scala, как класс Inner case может последовательно переопределять метод? - PullRequest
2 голосов
/ 23 апреля 2019

Недавно я обнаружил, что компилятор Scala имеет интересную особенность для класса case: поскольку он генерирует как класс, так и сигнатуру объекта, если он определен как внутренний класс, его можно использовать для переопределения определения абстрактного типа и определения функции его суперкласс с минимальным стандартным кодом, вот пример:

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 параметризовано, то ни внутренний класс падежа, ни внутренний объект не могут его переопределить: функция apply внутреннего объекта автоматически не расширяется до метода ее внешний класс:

  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 предназначен для связи случая 1, а не случая 2?

Ответы [ 3 ]

4 голосов
/ 23 апреля 2019

Это не особенно разработан вообще;или это так, но не так, как вы думаете.Вы не переопределяете def AA() с помощью метода, который создает 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

Существенными вариантами дизайна являются "object s может переопределить без параметров def s" (и так может vals, var s и, конечно, без параметров def s) и "case class es автоматически генерируют object s".«Внутренние case class переопределяют методы с одинаковыми именами во внешнем классе с помощью своих конструкторов», это не одно из правил Scala.object O содержит case class I и object I, а реферат def I(): AnyRef переопределяется для возврата указанного object I.Содержимое object I не имеет значения, потому что def I() должно возвращать только 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, которого ему не хватает.

1 голос
/ 25 апреля 2019

Я предполагаю, что это просто связано с ролью apply в классах случаев.См. Метод применения класса Case по умолчанию SSA удовлетворяет SS_Clear.AA через сопутствующий объект SSA (SSA.apply).

Когда вы добавляете параметр в метод, которого у вас больше нетметод 0-параметра apply для выполнения этой роли.

0 голосов
/ 23 июня 2019

ОК. Я нашел канонический способ сделать это:

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

Конец истории :) Один класс дел переопределяет 2 объявления?Нет проблем

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...