Сопоставление шаблона Scala с манифестом

Эта замечательная ежедневная статья о Scala описывает, как преодолеть стирание типов при сопоставлении. Я пытаюсь применить эту технику для преобразования IndexesSeq параметризованных типов, но совпадения не удались. Почему это так и как я могу это исправить?

object Example extends App{
    class TableColumn[T](
        val values: IndexedSeq[T], 
        val name: Option[String] = None
    )(implicit val m: Manifest[T])

    class Def[C](implicit desired : Manifest[C]) {
        def unapply[X](c : X)(implicit m : Manifest[X]) : Option[C] = {
            //println("m.toString+", "+desired.toString)
            def sameArgs = desired.typeArguments.zip(m.typeArguments).forall {
                case (desired,actual) => desired >:> actual
            }
            if (desired >:> m && sameArgs) Some(c.asInstanceOf[C])
            else None
         }
    }

    val IntTableColumn = new Def[TableColumn[Int]]
    val DoubleTableColumn = new Def[TableColumn[Double]]

    class Analysis(data: IndexedSeq[TableColumn[_]]){
        val transformedData = data.map{_ match{
            case IntTableColumn(tc) => println("Column of Int! "+ tc)
            case DoubleTableColumn(tc) => println("Column of Double! "+ tc)
            case _ => println("no match")
        }}
    }

    new Analysis(IndexedSeq(
            new TableColumn(IndexedSeq(1,2,3)),
            new TableColumn(IndexedSeq(1.0,2.0,3.0))
    ))
}

Если я раскомментирую строку в Def, я увижу такие строки, как

prototype.Example$TableColumn[_ <: Any], prototype.Example$TableColumn[Int]

предполагая, что проблема заключается в _ в конструкторе анализа, но я не знаю, что еще туда добавить.


person Pengin    schedule 14.08.2012    source источник
comment
Вы читали в статье эту фразу: Критично обращать внимание на использование typeArguments манифеста. Это возвращает список манифестов каждого typeArgument. Вы не можете просто сравнить желаемое == m, потому что явные сравнения не являются глубокими. В этом коде есть недостаток, заключающийся в том, что он обрабатывает только дженерики глубиной 1 уровня. Сопутствующее обсуждение не скажет вам точно, как это исправить, но должно сказать вам, почему это не работает.   -  person Rex Kerr    schedule 14.08.2012
comment
@Rex: я запутался в некоторых тонкостях статьи, но теперь вы указали на это, я вижу проблему и подумаю, могу ли я решить ее каким-то другим способом. Спасибо   -  person Pengin    schedule 14.08.2012
comment
На самом деле есть две проблемы: одна — вложенность, а другая — наличие нескольких типов в одном списке, что требует расширения типов. Я думаю, вам понадобится несколько isAssignableFrom в окончательном решении, но, к сожалению, у меня сейчас нет времени писать решение самостоятельно.   -  person Rex Kerr    schedule 14.08.2012
comment
Поскольку вы нашли ответ, вы должны сами ответить на свой вопрос, чтобы он не остался без ответа.   -  person Urban Vagabond    schedule 24.12.2013


Ответы (1)


Благодаря комментариям Рекса Керра я собрал кое-что, что, как мне кажется, работает. Вероятно, это можно сделать более элегантно/в целом, но, похоже, на данный момент работа выполнена:

object Example extends App{
    class TableColumn[T](
            val values: IndexedSeq[T], 
            val name: Option[String] = None
    )(implicit val m: Manifest[T])

    class TableColumnMatcher[T](implicit desired: Manifest[T]){
        def unapply(tc: TableColumn[_]): Option[TableColumn[T]] = {
            if(tc.m == desired) Some(tc.asInstanceOf[TableColumn[T]])
            else None
        }
    }
    object TableColumnMatcher{
        lazy val IntTC = new TableColumnMatcher[Int]
        lazy val DoubleTC = new TableColumnMatcher[Double]
    }


    class Analysis(data: IndexedSeq[TableColumn[_]]){
        import TableColumnMatcher._
        val transformedData = data.map{_ match{
            case IntTC(tc) => println("Column of Ints!"); 
            case DoubleTC(tc) => println("Column of Doubles!")
            case _ => println("no match")
        }}
    }

    new Analysis(IndexedSeq(
            new TableColumn(IndexedSeq(1,2,3)),
            new TableColumn(IndexedSeq(1.0,2.0,3.0))
    ))
}
person Pengin    schedule 24.12.2013