2012-08-14 18 views
7

This great daily Scala article opisuje, w jaki sposób przezwyciężyć wymazywanie typu w dopasowaniu. Próbuję zastosować tę technikę do transformacji IndexesSeq sparametryzowanych typów, ale dopasowania się nie udają. Dlaczego tak jest i jak mogę to naprawić?Dopasowanie wzorca Scala z manifestem

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)) 
    )) 
} 

Gdybym odkomentuj linię Def potem widzę linie takie jak

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

sugeruje, że _ w konstruktorze analizy jest problem, ale nie wiem, co jeszcze umieścić w tam.

+2

Czytałaś w artykule tę frazę: „Bardzo ważne jest, aby zauważyć wykorzystanie typeArguments manifestu. To zwraca listę manifestów każdego typuArgument.Nie można po prostu porównać pożądanego == m, ponieważ oczywiste porównania nie są głębokie.Nie ma słabości w tym kodzie, że obsługuje tylko generics, które są 1 poziom głębokości. "? Okoliczna dyskusja nie powie Ci dokładnie, jak to naprawić, ale powinna Ci powiedzieć, dlaczego to nie działa. –

+0

@Rex: Zagubiłem się w kilku drobniejszych punktach artykułu, ale teraz zwracasz na to uwagę, widzę problem i zastanawiam się, czy mogę go rozwiązać w jakiś inny sposób. Dzięki – Pengin

+1

Istnieją dwa problemy: jeden to zagnieżdżanie, a drugi to to, że masz wiele typów na jednej liście, co wymaga poszerzenia typu. Myślę, że w ostatecznym rozwiązaniu będziesz chciał mieć 'isAssignableFrom', ale niestety nie mam teraz czasu, aby napisać rozwiązanie samemu. –

Odpowiedz

1

Dzięki komentarzom Rex Kerr utkwiłem razem coś, co moim zdaniem działa. Można to chyba zrobić bardziej elegancko/ogólnie, ale wydaje się, że to zadanie na teraz:

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)) 
    )) 
} 
Powiązane problemy