2010-05-13 14 views
39

W Scala, mogę zrobić caseclass, case class Foo(x:Int), a następnie umieścić go na liście tak:Operator "::" Scali, jak to działa?

List(Foo(42)) 

Teraz nic dziwnego tutaj. Poniższe jest dla mnie dziwne. Operator :: jest funkcją na liście, prawda? Z dowolną funkcją z jednym argumentem w Scali, mogę ją nazwać notacją infiksową. Przykład to 1 + 2 jest funkcją (+) na obiekcie Int. Zdefiniowana przeze mnie klasa Foo nie ma operatora ::, więc w jaki sposób jest to możliwe?

Foo(40) :: List(Foo(2)) 

w Scala 2.8 RC1, uzyskać następujące wyjściowe z interaktywnym wierszu:

scala> case class Foo(x:Int) 
defined class Foo 

scala> Foo(40) :: List(Foo(2)) 
res2: List[Foo] = List(Foo(40), Foo(2)) 

mogę iść i go używać, ale to, co jest wyjaśnienie?

Odpowiedz

39

Z Spec:

6.12.3 InfixOperations Operator infix może być dowolna identyfikator. Operatory infiksów mają priorytet i powiązanie zdefiniowane w następujący sposób: .

...

asocjatywność od operatora jest określana przez ostatniego charakterze operatora. Operatory kończące się okrężnicą ":" są skojarzeniami prawostronnymi. Wszystkie inne operatory są lewostronne.

Zawsze można zobaczyć, jak te zasady są stosowane w Scala drukując program po to został przez „typer” fazy kompilatora:

scala -Xprint:typer -e "1 :: Nil" 

val r: List[Int] = { 
    <synthetic> val x$1: Int = 1; 
    immutable.this.Nil.::[Int](x$1) 
}; 
+1

Obowiązuje również dla przekazywania parametrów typu do typów konstruktorów. Powiedzmy, że masz klasę przypadków: [H, T] (głowa: H, ogon: T); i klasa SomeType [A]; wtedy możesz zrobić zarówno nowy SomeType [:: [String, Int]] ("a", 3) i nowy SomeType [H :: T] ("a", 3) – lisak

19

Kończy się :. I to jest znak, że ta funkcja jest zdefiniowana w klasie po prawej (w klasie List).

W twoim przykładzie jest to List(Foo(2)).::(Foo(40)), a nie Foo(40).::(List(Foo(2))).

+4

Innymi słowy, 'a ::::: b' (po prostu głupie) jest tym samym, co' b. ::::: (a) '. Dodatkowo, metody, których nazwy kończą się dwukropkiem i używane w stylu infiksów, kojarzą się raczej z prawą, a nie z lewą, więc 'a :: b :: c' jest tym samym co' c.::(b.::(a))) ' –

12

Klasa Foo Właśnie zdefiniowanej nie mieć operatorowi ::, tak jak jest to możliwe po :

Foo(40) :: List(Foo(2))

Jeśli nazwa metody kończy się dwukropkiem (:) metoda jest wywołany na prawego argumentu, który jest w tym przypadku. Jeśli nazwa metody nie kończy się dwukropkiem, metoda jest wywoływana na lewym argumencie. Na przykład a + b, + jest wywoływana na a.

Tak, w twoim przykładzie, :: jest metodą na jego prawym argumencie, który jest List.

15

Jednym z aspektów brakuje w odpowiedzi udzielonych jest to, że w celu wspierania :: w wyrażeniach Pattern Matching:

List(1,2) match { 
    case x :: xs => println(x + " " + xs) 
    case _ => println("") 
} 

A class :: is defined:

final case class ::[B](private var hd: B, private[scala] var tl: List[B]) 

tak case ::(x,xs) będzie produkować ten sam rezultat. Wyrażenie case x :: xs działa, ponieważ domyślny ekstraktor :: jest zdefiniowany dla klasy sprawy i można go użyć jako infiks.