Scala - Chỉ số
Một đặc điểm đóng gói các định nghĩa phương thức và trường, sau đó có thể được sử dụng lại bằng cách trộn chúng vào các lớp. Không giống như kế thừa lớp, trong đó mỗi lớp phải kế thừa chỉ từ một lớp cha, một lớp có thể kết hợp với bất kỳ số lượng đặc điểm nào.
Các đặc điểm được sử dụng để xác định các loại đối tượng bằng cách chỉ định chữ ký của các phương thức được hỗ trợ. Scala cũng cho phép các đặc điểm được thực hiện một phần nhưng các đặc điểm có thể không có tham số xây dựng.
Một định nghĩa đặc điểm trông giống như một định nghĩa lớp ngoại trừ việc nó sử dụng từ khóa trait. Sau đây là cú pháp ví dụ cơ bản của đặc điểm.
Cú pháp
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}
Đặc điểm này bao gồm hai phương pháp isEqual và isNotEqual. Ở đây, chúng tôi chưa đưa ra bất kỳ triển khai nào cho isEqual khi một phương thức khác có triển khai. Các lớp con mở rộng một đặc điểm có thể cung cấp triển khai cho các phương thức chưa được triển khai. Vì vậy, một đặc điểm rất giống với những gì chúng ta cóabstract classes trong Java.
Hãy để chúng tôi giả sử một ví dụ về đặc điểm Equal chứa hai phương pháp isEqual() và isNotEqual(). Đặc điểmEqual chứa một phương pháp được triển khai đó là isEqual() vì vậy khi người dùng xác định lớp Point mở rộng đặc điểm Equal, triển khai đến isEqual() phương pháp trong Point lớp học nên được cung cấp.
Ở đây cần phải biết hai phương pháp quan trọng của Scala, được sử dụng trong ví dụ sau.
obj.isInstanceOf [Point] Để kiểm tra Loại đối tượng và Điểm có giống nhau không.
obj.asInstanceOf [Point] nghĩa là ép kiểu chính xác bằng cách lấy kiểu obj của đối tượng và trả về cùng kiểu obj như kiểu Point.
Hãy thử chương trình ví dụ sau để triển khai các đặc điểm.
Thí dụ
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}
class Point(xc: Int, yc: Int) extends Equal {
var x: Int = xc
var y: Int = yc
def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == y
}
object Demo {
def main(args: Array[String]) {
val p1 = new Point(2, 3)
val p2 = new Point(2, 4)
val p3 = new Point(3, 3)
println(p1.isNotEqual(p2))
println(p1.isNotEqual(p3))
println(p1.isNotEqual(2))
}
}
Lưu chương trình trên vào Demo.scala. Các lệnh sau được sử dụng để biên dịch và thực thi chương trình này.
Chỉ huy
\>scalac Demo.scala
\>scala Demo
Đầu ra
true
false
true
Các lớp giá trị và Đặc điểm chung
Các lớp giá trị là cơ chế mới trong Scala để tránh cấp phát các đối tượng thời gian chạy. Nó chứa một hàm tạo chính với chính xác mộtvaltham số. Nó chỉ chứa các phương thức (def) không được phép var, val, các lớp, đặc điểm hoặc đối tượng lồng nhau. Lớp giá trị không thể được mở rộng bởi một lớp khác. Điều này có thể thực hiện được bằng cách mở rộng lớp giá trị của bạn với AnyVal. Các loại dữ liệu tùy chỉnh an toàn mà không có chi phí thời gian chạy.
Chúng ta hãy lấy ví dụ về các lớp giá trị Cân nặng, Chiều cao, Email, Tuổi, v.v. Đối với tất cả các ví dụ này, không yêu cầu cấp phát bộ nhớ trong ứng dụng.
Một lớp giá trị không được phép mở rộng các đặc điểm. Để cho phép các lớp giá trị mở rộng các đặc điểm,universal traits được giới thiệu mở rộng cho Any.
Thí dụ
trait Printable extends Any {
def print(): Unit = println(this)
}
class Wrapper(val underlying: Int) extends AnyVal with Printable
object Demo {
def main(args: Array[String]) {
val w = new Wrapper(3)
w.print() // actually requires instantiating a Wrapper instance
}
}
Lưu chương trình trên vào Demo.scala. Các lệnh sau được sử dụng để biên dịch và thực thi chương trình này.
Chỉ huy
\>scalac Demo.scala
\>scala Demo
Đầu ra
Nó sẽ cung cấp cho bạn mã băm của lớp Wrapper.
Wrapper@13
Khi nào thì sử dụng đặc điểm?
Không có quy tắc chắc chắn, nhưng đây là một số nguyên tắc cần xem xét -
Nếu hành vi sẽ không được sử dụng lại, thì hãy biến nó thành một lớp cụ thể. Rốt cuộc, nó không phải là hành vi có thể tái sử dụng.
Nếu nó có thể được sử dụng lại trong nhiều lớp, không liên quan, hãy biến nó thành một đặc điểm. Chỉ các tính trạng có thể được trộn lẫn vào các phần khác nhau của hệ thống phân cấp lớp.
Nếu bạn muốn inherit từ nó trong mã Java, sử dụng một lớp trừu tượng.
Nếu bạn định phân phối nó ở dạng đã biên dịch và bạn mong đợi các nhóm bên ngoài viết các lớp kế thừa từ nó, bạn có thể hướng tới sử dụng một lớp trừu tượng.
Nếu hiệu quả là rất quan trọng, hãy hướng tới việc sử dụng một lớp học.