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 apply
và unapply
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
Vì 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ế.
http://blog.lunatech.com/2011/11/25/scala-list-extractor-demystified giải thích tốt cách hoạt động –
@ 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
@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