openlang

Как унаследовать класс внутри другого класса?

Здравствуйте,

В пакете, код которого я не могу менять, есть такая иерархия классов:

class Outer:
    class Inner(number: Int):
        ???

Я хочу добавить удобную обёртку вокруг Inner, но из-за зависимости Inner от внешнего экземпляра пока удалось разместить её только в подклассе внешнего класса:

new Outer:
    case class InnerCase(number: Int) extends Inner(number):
        ???

    (new InnerCase(3)).copy() // sample usage

К сожалению, если наследовать Outer в нескольких местах, этот вспомогательный case class приходится повторять внутри каждого нового подкласса. Чтобы не дублировать определение снова и снова, хотелось бы иметь класс, пригодный для произвольного Outer#Inner. Вот что я попробовал:

case class InnerCase(number: Int)(owner: Outer) extends owner.Inner(number):
    ???

new Outer:
    host =>
    InnerCase(3)(host).copy()(host)

new Outer:
    host =>
    val instance = InnerCase(4)(host).copy()(host)
    val widened: Inner = instance // line causing trouble

Но при полиморфном использовании InnerCase там, где требуется Inner, получаю такую диагностику:

Found: InnerCase
Required: Inner

Я всё ещё совсем новичок в Scala, так что наверняка есть более удачный способ сделать задуманное. Вероятно, существует теоретическое объяснение того, почему мой прямой подход нарушает систему типов. В любом случае буду очень рад подсказкам о «правильном» наследовании внутреннего класса.

Переведено с английскогоПоказать оригинал

Разговор продолжается 1

Следуя доводам
  1. Ссылка на ответ

    case class InnerCase(number: Int)(owner: Outer) extends owner.Inner(number): ???

    Это вообще не скомпилируется в нынешней Scala 3. Ссылаться на параметр конструктора из родительского типа некорректно с точки зрения системы типов. В трекере компилятора Scala 3 это объясняется в issue 16270 о небезопасном появлении параметров конструктора в родительских типах. Последующие проблемы со старыми компиляторами, включая вашу, часто вытекают из этой некорректности.

    Попробуйте организовать код так:

    class Outer:
        class Inner(number: Int):
            ???
    
    final class Holder[O <: Outer](val owner: O):
        case class InnerCase(number: Int) extends owner.Inner(number):
            ???
    
    new Outer:
        host =>
        Holder[this.type](this).InnerCase(3).copy()
    
    new Outer:
        host =>
        val holder: Holder[this.type] = Holder(this)
        val instance = holder.InnerCase(4).copy()
        val widened: Inner = instance // works here
    Переведено с английскогоПоказать оригинал

Другие стороны того же вопроса

  1. Сравнение привязок have и let в Lean4

    Я заметил, что эти два выражения и ведут себя одинаково. То же происходит при доказательстве теорем. Они взаимозаменяемы? В ч…

    Ответы 3Последняя активность lean-4
  2. Инициализация TypeScript Map со значениями в виде массивов строк

    Создаю Map, в котором каждая запись содержит массив строк. Как одновременно задать его тип и инициализировать одним выражение…

    Ответы 2Последняя активность typescript
  3. Контракт вызываемой функции в Typescript

    Почему Typescript принимает определение моей функции, хотя оно отличается от сигнатуры интерфейса, но сообщает о проблеме, ко…

    Ответы 2Последняя активность typescript