Обращаясь к типу внутреннего класса в Scala

Следующий код пытается подражать Полиморфное встраивание DSL: вместо того, чтобы давать поведение в Inner, оно закодировано в useInner метода его вмещающего класса. Я добавил метод enclosing, чтобы пользователь мог хранить ссылки только на экземпляры Inner, но всегда может получить свой закрытый экземпляр. Таким образом, все экземпляры Inner из определенного экземпляра Outer привязаны только к одному поведению (но он нужен здесь).

abstract class Outer {
  sealed class Inner {
    def enclosing = Outer.this
  }
 def useInner(x:Inner) : Boolean
}

def toBoolean(x:Outer#Inner) : Boolean = x.enclosing.useInner(x)

Он не компилируется, и scala 2.8 жалуется на:

type mismatch; found: sandbox.Outer#Inner
               required: _81.Inner where val _81:sandbox.Outer

Из Программирование Scala: Вложенные классы и Прогулка по Scala: Inner Classes, мне кажется, что проблема заключается в том, что useInner ожидает в качестве аргумента экземпляр Inner из конкретного экземпляра Outer.

Какое истинное объяснение и как решить эту проблему?

Ответы

Ответ 1

Я предполагаю, что тип Inner похож на тип this.Inner. Outer # Inner не зависит от внешнего экземпляра (не зависящего от пути типа).

abstract class Outer {
  sealed class Inner {
    def enclosing = Outer.this
  }
  def useInner(x:Outer#Inner) : Boolean
}

def toBoolean(x:Outer#Inner) : Boolean = x.enclosing.useInner(x)

Ответ 2

Проблема заключается в том, как вы описываете, что useInner ожидает Inner конкретного экземпляра Outer. Поскольку enclosing возвращает общий Outer, не существует способа связать обе вместе, что я знаю.

Вы можете заставить его, однако:

def toBoolean(x: Outer#Inner): Boolean = {
  val outer = x.enclosing
  outer.useInner(x.asInstanceOf[outer.Inner])
}

Ответ 3

Вы также можете определить свой член следующим образом:

def useInner(x:Outer#Inner) : Boolean

Или вы можете написать вот так:

abstract class Outer {
    class InnerImpl {
        def enclosing = Outer.this
    }
    final type Inner = Outer#InnerImpl
    def useInner(x:Inner) : Boolean
}