2011-09-02 11 views
11

Plik:Ostrzeżenie dotyczące argumentu niezaznaczonego typu w tym dopasowaniu wzorca Scala?

object Test extends App { 
    val obj = List(1,2,3) : Object 
    val res = obj match { 
     case Seq(1,2,3) => "first" 
     case _ => "other" 
    } 
    println(res) 
} 

Daje to ostrzeżenie:

Test.scala:6: warning: non variable type-argument A in type pattern Seq[A] 
is unchecked since it is eliminated by erasure 
    case Seq(1,2,3) => "first" 

Scala wersji 2.9.0.1.

Nie widzę potrzeby użycia parametru wymazanego typu do wykonania dopasowania. Pierwszy przypadek, że klauzula ta jest przeznaczona do zapytać, czy obj jest sekwencyjny z 3 elementów równa 1, 2 i 3.

chciałbym zrozumieć to ostrzeżenie gdybym napisał coś takiego:

case strings : Seq[String] => ... 

Dlaczego otrzymuję ostrzeżenie i jaki jest dobry sposób na jego odejście?

Nawiasem mówiąc, chcę dopasować coś do statycznego typu obiektu. W prawdziwym kodzie parsuję coś w rodzaju bazy danych Lisp - może to być ciąg, ciąg wzorców, symbol, liczba itd.

+0

Na ciekawą notatkę, Scala Wersja 2.8.1 nie daje tego ostrzeżenia w tym przypadku – thoredge

+0

@thoredge, domyślam się, że ostrzeżenie w wersji 2.9.0 było prawdopodobnie poprawą. Nie wiem, czy ten konkretny przypadek został przewidziany. – huynhjl

Odpowiedz

5

Oto kilka informacji na temat tego, co dzieje się za sceną. Rozważmy następujący kod:

class Test { 
    new Object match { case x: Seq[Int] => true } 
    new Object match { case Seq(1) => true } 
} 

Jeśli skompilować z scalac -Xprint:12 -unchecked zobaczysz kod tuż przed fazą skasowaniem (id 13). Dla pierwszego typu wzoru, zobaczysz coś takiego:

<synthetic> val temp1: java.lang.Object = new java.lang.Object(); 
if (temp1.isInstanceOf[Seq[Int]]()) 

dla wzoru Seqodprowadzającej, zobaczysz coś takiego:

<synthetic> val temp3: java.lang.Object = new java.lang.Object(); 
if (temp3.isInstanceOf[Seq[A]]()) { 
    <synthetic> val temp4: Seq[A] = temp3.asInstanceOf[Seq[A]](); 
    <synthetic> val temp5: Some[Seq[A]] = collection.this.Seq.unapplySeq[A](temp4); 
    // ... 
} 

w obu przypadkach, nie jest typem sprawdź, czy obiekt jest typu Seq (Seq[Int] i Seq[A]). Parametry typu zostaną wyeliminowane podczas fazy wymazywania. Tak więc ostrzeżenie. Mimo że druga może być nieoczekiwana, sensowne jest sprawdzenie typu, ponieważ jeśli obiekt nie jest typu Seq, klauzula nie będzie zgodna, a JVM może przejść do następnej klauzuli. Jeśli typ jest zgodny, to obiekt można odrzucić do Seq i unapplySeq można wywołać.


RE: komentarz thoredge na sprawdzanie typu. Być może mówimy o różnych rzeczach. Ja po prostu mówiąc, że:

(o: Object) match { 
    case Seq(i) => println("seq " + i) 
    case Array(i) => println("array " + i) 
} 

przekłada się na coś takiego:

if (o.isInstanceOf[Seq[_]]) { // type check 
    val temp1 = o.asInstanceOf[Seq[_]] // cast 
    // verify that temp1 is of length 1 and println("seq " + temp1(0)) 
} else if (o.isInstanceOf[Array[_]]) { // type check 
    val temp1 = o.asInstanceOf[Array[_]] // cast 
    // verify that temp1 is of length 1 and println("array " + temp1(0)) 
} 

Kontrola typ jest używany tak, że gdy obsada odbywa się tam nie jest wyjątkiem klasy obsada.

czy ostrzeżenie non zmienna typu argumentu A na typ wzoru seq [A] jest zaznaczone, ponieważ jest on wyeliminowany przez skasowaniem jest uzasadnione i czy nie byłoby sprawy, w których mogłoby istnieć wyjątek klasa obsada nawet z sprawdź typ, nie wiem.

Edycja: tutaj jest przykład:

object SeqSumIs10 { 
    def unapply(seq: Seq[Int]) = if (seq.sum == 10) Some(seq) else None 
} 

(Seq("a"): Object) match { 
    case SeqSumIs10(seq) => println("seq.sum is 10 " + seq) 
} 
// ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
+1

Czy to jest błąd? Kontrola typu jest w tym przypadku tylko optymalizacją. – thoredge

+0

@thoredge, bez sprawdzenia typu, otrzymasz wyjątek * ClassCastException *, gdy obiekt nie jest typu 'Seq' kontra próba dopasowania do kolejnych klauzul. – huynhjl

+0

Nie otrzymuję wyjątku ClassCaseException, jeśli zmienię obiekt na mapę (1 -> 2, 2 -> 3), mapę ("1" -> "2", "2" -> "3"); lub "" w tym przypadku – thoredge

4

Deklarowanie obiektu mecz poza przynajmniej sprawia, że ​​odejdzie, ale nie jestem pewien, dlaczego:

class App 
    object Test extends App { 
    val obj = List(1,2,3) : Object 
    val MatchMe = Seq(1,2,3) 
    val res = obj match { 
    case MatchMe => "first" 
    case _ => "other" 
    } 
    println(res) 
} 
+2

Tak, dobrze. Dzieje się tak, ponieważ w tym przypadku używa * stabilnego wzorca identyfikatora *, a te kompilują się tylko do testu równości (według specyfikacji językowej), bez konieczności rzutowania. Jeśli chcesz wiązać zmienne, nie masz szczęścia. – huynhjl

+0

Dobrze wiedzieć, ale tak, potrzebuję powiązać zmienne. –

+1

Co, jeśli pasuję do typu (np. 'Seq [Int]') i jakakolwiek sekwencja liczb całkowitych jest uważana za prawidłową zgodność (nie tylko (1 2, 3))? – Ivan

Powiązane problemy