2013-06-07 2 views
3

Я хочу реализовать шаблон обогащения my-library для внутреннего класса, который будет работать для любого экземпляра внешнего класса. Что-то вроде этого:Обогащение внутреннего класса

class Outer { 
    class Inner(val x: Option[Inner] = None) { 
    def test(y: Inner) {} 
    } 
} 

implicit class ExtInner(inner: Outer#Inner) { 
    def get = inner.x.get 
} 

val outer = new Outer 
val inner = new outer.Inner(Some(new outer.Inner)) 
inner.test(inner.get) 

Этот код не будет компилироваться, из-за несоответствия типа: get возвращает объект типа Outer#Inner но test ожидает outer.Inner.

У меня есть два способа заставить его работать, но оба связаны с использованием asInstanceOf, которого я бы хотел избежать. Первый из них просто бросить результат get к outer.Inner:

inner.test(inner.get.asInstanceOf[outer.Inner]) 

второй является немного более универсальным и делает кастинг в ExtInner:

implicit class ExtInner[T <: Outer#Inner](inner: T) { 
    def get = inner.x.get.asInstanceOf[T] 
} 

Есть ли лучший способ обогатить внутренний класс, поэтому не нужно делать кастинг?

ответ

1

Как насчет:

object Test extends App { 
    class Outer { 
    class Inner(val x: Option[Inner] = None) { 
     def test(y: Inner) { println(s"$toString testing $y") } 
    } 
    implicit class ExtInner(val inner: Inner) { 
     def get = inner.x.get 
    } 
    } 

    val outer = new Outer 
    val inner = new outer.Inner(Some(new outer.Inner)) 
    import outer._ 
    inner.test(inner.get) 
} 

или просто улучшить внешний-х колб:

implicit class ExtInner(val inner: outer.Inner) { 
    def get = inner.x.get 
    } 

Кроме того, я чувствую, что вы можете вызвать метод таким образом, но это не будет выводить Пары внешнего типа одноточечно .type, чтобы вызвать неявное.

implicit class ExtInner[A <: Outer with Singleton](val inner: A#Inner) { 
    def get: A#Inner = inner.x.get 
    } 
    inner.test(ExtInner[outer.type](inner).get) 
+0

Pimp my library pattern предполагает, что класс 'Outer' не может быть изменен, поэтому использование' ExtInner' внутри класса 'Outer' на самом деле не является решением. Если 'ExtInner' принимает' external.Inner' вместо 'Outer # Inner', привязывает его к конкретному экземпляру, что нежелательно, потому что нам нужно будет определить новое неявное преобразование для каждого экземпляра класса' Outer'. – gleb

+0

Тогда вы должны принять мой третий ответ, что вы не можете получить неявное применение. Это аналогично преобразованию регулярных выражений в мини-торт Parsers, поэтому он должен быть обычным прецедентом. Там всегда есть отражение и макросы. –

+0

Ваш третий ответ выполняет работу без кастинга, хотя для этого требуется немного кода шаблона. Можете ли вы прокомментировать, почему нам нужно «с Синглтоном», похоже, он работает без него? – gleb

Смежные вопросы