2011-09-14 11 views
11

Mam mały problem z dopasowaniem wzorca do obiektu w Scali, gdy jest sparametryzowany za pomocą w pełni kwalifikowanej nazwy klasy. Oparte jest to na Scali 2.9.0.1. Ktoś wie, co jest nie tak z tym kodem?Scala: problem dopasowania wzorca z całkowicie kwalifikowanymi nazwami klas w parametryzacji

scala> "foo" match { 
| case y : Seq[Integer] => 
| case y : Seq[java.lang.Integer] => 
<console>:3: error: ']' expected but '.' found. 
    case y : Seq[java.lang.Integer] => 

Dlaczego pierwsza wersja działa, ale druga nie działa? Problem pojawia się tylko wtedy, gdy do parametryzacji jest używana pełna nazwa klasy.

Odpowiedz

12

Z Scala Language Specification, punkt 8.1 Wzory, identyfikator po: musi być to, co jest określane jako typ wzoru, zdefiniowane w rozdziale 8.2:

Type patterns consist of types, type variables, and wildcards. A type pattern T is of one of the following forms:

...

A parameterized type pattern T [a(1), . . . , a(n)], where the a(i) are type variable patterns or wildcards _. This type pattern matches all values which match T for some arbitrary instantiation of the type variables and wildcards. The bounds or alias type of these type variable are determined as described in (§8.3).

...

A type variable pattern is a simple identifier which starts with a lower case letter. However, the predefined primitive type aliases unit, boolean, byte, short, char, int, long, float, and double are not classified as type variable patterns.

Tak więc, składnie, nie można używać w pełni kwalifikowanej klasy jako wzorca zmiennej typu W TYM POZYCJI. Możesz jednak użyć aliasu typu, więc:

type JavaInt = java.lang.Integer 
List(new java.lang.Integer(5)) match { 
    case y: Seq[JavaInt] => 6 
    case _ => 7 
} 

powróci 6 zgodnie z oczekiwaniami. Problem polega na tym, że jak Alan Burlison zwraca uwagę, poniższe również zwraca 6:

List("foobar") match { 
    case y: Seq[JavaInt] => 6 
    case _ => 7 
} 

, ponieważ typ jest usuwany. Możesz to zobaczyć, uruchamiając REPL, lub skalak z opcją -unchecked.

+0

Wow. Uderzyłem to dzisiaj i ostatecznie znalazłem to pytanie. Nie miałem pojęcia, że ​​w Scali istnieje nawet "wzór zmiennej typu". Co jeszcze ukrywa się przed mną w SLS ...? –

+2

Niektóre z pisanek aktywują się tylko w 1/4 i Wielkanoc. –

+0

Zacząłem wątek na ten temat na https://groups.google.com/d/msg/scala-language/2PNDjkI47Ao/MCQw7RzNUwcJ –

3

W rzeczywistości Twój pierwszy przykład również nie działa. Po uruchomieniu rEPL z -unchecked, zobaczysz następujący błąd:

warning: non variable type-argument Integer in type pattern Seq[Integer] is unchecked since it is eliminated by erasure

Więc nie można rzeczywiście zrobić, co chce robić - w czasie wykonywania nie ma różnicy między List [Integer ] i listę [AnythingElse], więc nie można dopasować do niej wzorca. Możesz być w stanie to zrobić z oczywistego, zobacz http://ofps.oreilly.com/titles/9780596155957/ScalasTypeSystem.html#Manifests i http://www.scala-blogs.org/2008/10/manifests-reified-types.html

+0

Nie sądzę, że chodziło o typ wymazania. Co powiesz na to: '" foo ".asInstanceOf [Any] match {'
'case x: Seq [Integer] =>'
'case y: Seq [java.lang.Integer] =>'
'}' – Jamil

+0

@Jamil, Wierzę, że 'Seq [java.lang.Integer]' jest po prostu błędem składni. Wierzę, że kompilator traktuje 'java.lang.Integer' jako identyfikator i nie może zawierać w nich kropek. Możesz to zademonstrować, otaczając 'java.lang.Integer' w podobieństwach - zostanie on skompilowany, ale nadal będziesz otrzymywać ostrzeżenie o tym usuwaniu, które robisz za pomocą zwykłego' Integer'. Zgadzam się, że błąd jest mylący, ale nie jest to aż tak zaskakujące, biorąc pod uwagę, że tak naprawdę nie możesz zrobić tego, co @Frank próbuje mimo wszystko. –

+0

'java.lang.Integer' jest typem, a nie zmienną. Co więcej, Scala wiąże się ze zmienną, gdy używasz wzorca Konstruktora, krotki lub sekwencji itp. Dziwne, jeśli używam aliasu 'type myint = java.lang.Integer' Scala nie narzeka – Jamil

Powiązane problemy