2014-09-20 13 views
5

thế nào là người đứng đầu và đuôi xác định trong tuyên bố sau:Kết hợp mẫu Scala Cons xác định đầu và đuôi của Danh sách như thế nào?

val head::tail = List(1,2,3,4); 
//head: 1 tail: List(2,3,4) 

Nên không có được một số đoạn mã mà chiết xuất các yếu tố đầu tiên làm Trưởng ban và trả về đuôi như một danh sách mới. Tôi đã được chải qua mã thư viện chuẩn Scala và tôi không thể tìm thấy/hiểu làm thế nào/nơi này được thực hiện.

+4

http://blog.lunatech.com/2011/11/25/scala-list-extractor-demystified giải thích tốt cách hoạt động –

+0

@ eugene-zhulenev, cảm ơn bạn đã liên kết. Đây là chỗ trên. Lớp Cons case tự động cung cấp các phương tiện để xây dựng một thể hiện List và deconstruct nó thành một cái đầu và một cái đuôi. – poissondist

+0

@poissondist liên kết từ eugene zhulenev bị hỏng. Bạn nghĩ gì về câu trả lời của tôi dưới đây? – metasim

Trả lời

0

Cấu trúc Scala có liên quan ở đây là Extractor. Biểu tượng :: là gì, nhưng một trường hợp lớp học trong Scala, nơi một phương pháp unapply tồn tại trên đối tượng đồng hành của nó để làm cho phép thuật khai thác xảy ra. Here là một hướng dẫn chuyên sâu về các bộ giải nén. Nhưng đây là tóm tắt:

Bất cứ khi nào bạn muốn "giải nén" nội dung của một lớp, hoặc cho biến ràng buộc hoặc là một phần của khớp mẫu, trình biên dịch sẽ tìm phương thức unapply trên bất kỳ biểu tượng nào ở phía bên tay trái của biểu thức. Đây có thể là một đối tượng, một đối tượng đồng hành lớp vỏ bọc (như ::, trong câu hỏi của bạn) hoặc một cá thể có một số unapply. Đối số cho unapply là loại đến để giải nén và loại trả về là một số Option của những gì đã được khai báo là cấu trúc và loại dự kiến. Trong mẫu phù hợp với một None cho biết không tìm thấy kết quả phù hợp. Trong liên kết biến, MatchError bị ném nếu kết quả là None.

Cách suy nghĩ tốt về unapply là nó là nghịch đảo của apply. Trường hợp unapply người nhận cú pháp gọi hàm, unapply là người nhận cuộc gọi vắt.

Để minh họa điều này hơn nữa, chúng ta hãy định nghĩa một lớp trường hợp đơn giản:

case class Cat(name: String, age: Int) 

Bởi vì nó là một lớp trường hợp, chúng tôi được tự động tạo ra applyunapply phương pháp trên đối tượng đồng, trong đó khoảng trông như thế này:

object Cat { 
    // compiler generated... 
    def apply(name: String, age: Int) = new Cat(name, age)  
    def unapply(aCat: Cat): Option[(String, Int)] = Some((aCat.name, aCat.age)) 
} 

Khi bạn tạo Cat qua đối tượng đồng hành, apply được gọi. Khi bạn giải nén các bộ phận cấu thành của một Cat, unapply được gọi là:

val mycat = Cat("freddy", 3) // `apply` called here 
... 
val Cat(name, age) = mycat // `unapply` called here 
... 
val animal: AnyRef = mycat 
val info = animal match { 
    case Cat(name, age) => "My pet " + name // `unapply` called here 
    case _ => "Not my pet" 
} 
// info: String = My pet freddy 

unapply lợi nhuận một Option, chúng tôi có rất nhiều năng lượng để viết nhổ có thể xử lý các trường hợp thú vị hơn, ví dụ, thử nghiệm cho dù các loại đến phù hợp với một số tiêu chí trước khi trích xuất các giá trị. Ví dụ, giả sử chúng ta muốn lấy tên của những con mèo "cũ".Người ta có thể làm điều này:

object OldCatName { 
    def unapply(aCat: Cat) = if (aCat.age >= 10) Some(aCat.name) else None 
} 

Cách sử dụng sẽ được giống như một tạo unapply:

val yourcat = Cat("betty", 12) 
... 
val OldCatName(name1) = yourcat 
// name1: String = "betty" 
val OldCatName(name2) = mycat 
// scala.MatchError: Cat(freddy,3) (of class Cat) 

MatchError s không phải là một điều tốt đẹp để cho phép, vì vậy hãy sử dụng mô hình phù hợp:

val conditions = Seq(mycat, yourcat) map { 
    case OldCatName(oldie) => s"$oldie is old" 
    case Cat(name, age) => s"At age $age $name is not old" 
} 
// conditions: Seq[String] = List(At age 3 freddy is not old, betty is old) 

Thêm một chút ma thuật liên quan đến phương pháp unapply cho :: là một số đường cú pháp cho phép val ::(head, tail) = ... được viết val head :: tail = ... thay thế.

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