2010-05-13 23 views
39

Trong Scala, tôi có thể làm cho một caseclass, case class Foo(x:Int), và sau đó đặt nó trong một danh sách như vậy:Nhà điều hành '::' của Scala, nó hoạt động như thế nào?

List(Foo(42)) 

Bây giờ, không có gì lạ ở đây. Sau đây là lạ với tôi. Nhà điều hành :: là một chức năng trong danh sách, phải không? Với bất kỳ chức năng nào với một đối số trong Scala, tôi có thể gọi nó bằng ký hiệu infix. Ví dụ là 1 + 2 là một hàm (+) trên đối tượng Int. Lớp học Foo Tôi vừa xác định không có nhà điều hành ::, vậy làm cách nào có thể làm như sau?

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

Trong Scala 2.8 RC1, tôi nhận được kết quả sau từ dấu nhắc tương tác:

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

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

tôi có thể tiếp tục và sử dụng nó, nhưng lời giải thích là gì?

Trả lời

39

Từ Spec:

6.12.3 InfixOperations Một nhà điều hành ghi có thể là một nhận dạng tùy ý. Các toán tử Infix có ưu tiên là và kết hợp được xác định như sau.

...

Các kết hợp của một nhà điều hành là xác định bởi ký tự cuối cùng của nhà điều hành. Các toán tử kết thúc bằng dấu hai chấm ‘:’ là kết hợp đúng. Tất cả các nhà khai thác khác đều liên kết trái.

Bạn luôn có thể xem như thế nào những quy tắc được áp dụng trong Scala bằng cách in các chương trình sau khi nó đã được thông qua 'typer' giai đoạn của trình biên dịch:

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

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

Nó cũng áp dụng cho việc truyền tham số kiểu để gõ các hàm tạo. Hãy nói rằng bạn có một trường hợp lớp :: [H, T] (đầu: H, đuôi: T); và lớp SomeType [A]; thì bạn có thể thực hiện cả SomeType mới [:: [String, Int]] ("a", 3) và SomeType mới [H :: T] ("a", 3) – lisak

19

Kết thúc bằng :. Và đó là dấu hiệu, rằng hàm này được định nghĩa trong lớp ở bên phải (trong lớp List ở đây).

Vì vậy, nó là List(Foo(2)).::(Foo(40)), không phải Foo(40).::(List(Foo(2))) trong ví dụ của bạn.

+4

Nói cách khác, 'a ::::: b' (chỉ để ngớ ngẩn) giống như' b. :::: :(a) '. Ngoài ra, các phương thức có tên kết thúc bằng dấu hai chấm và được sử dụng trong kiểu kết hợp infix ở bên phải, chứ không phải ở bên trái, vì vậy 'a :: b :: c' giống với' c.::(b.::(a))) ' –

12

Lớp Foo Tôi chỉ được xác định không có các nhà điều hành ::, vậy làm thế nào là sau càng tốt:

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

Nếu tên phương thức kết thúc bằng dấu hai chấm (:), phương thức được gọi trên toán hạng bên phải, đây là trường hợp tại đây. Nếu tên phương thức không kết thúc bằng dấu hai chấm, phương thức được gọi trên toán hạng bên trái. Ví dụ: a + b, + được gọi trên a.

Vì vậy, trong ví dụ của bạn, :: là một phương pháp trên toán hạng bên phải, là List.

15

Một khía cạnh còn thiếu trong các câu trả lời đưa ra là để hỗ trợ :: trong các biểu thức phù hợp với mô hình:

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

nên case ::(x,xs) sẽ tạo ra kết quả tương tự. Biểu thức case x :: xs hoạt động vì trình trích xuất mặc định :: được định nghĩa cho lớp vỏ và nó có thể được sử dụng.

Các vấn đề liên quan