Trong phần trước tôi đã giới thiệu cho bạn về Variance. Bạn nên đọc phần này trước khi vào bài viết này.
Typy Bound là các giới hạn trên các Type parameter hoặc Type Variable. Bằng việc sử dụng Type Bound, chúng ta có thể định nghĩa giới hạn Type Variable.
Ưu điểm của Type Bound
Type Bound mang đến cho chúng ta những lợi ích sau:
- Phát triển ứng dụng Type-safe
Type Bound
Scala hỗ trợ những Type Bound sau cho Type Variable
- Scala Upper Bounds
- Scala Lower Bounds
- Scala View Bounds
Scala Upper Bound
Trong Scala, chúng ta có thể định nghĩa Upper Bound trên Type Parameter như hình bên dưới đây:
Ở đây thì T là một Type Parameter và S là một Type. Bằng việc khái báo Upper Bound T <: S
nghĩa là Type Parameter hay T này phải giống với Type của S hoặc sub-type của S
Ví dụ
[T <: Ordered[T]]
Ở đây chúng ta đã định nghĩa Upper Bound từ Type Parameter T đến Ordered[T]. Do đó T phải là Ordered hoặc sub-type của Ordered.
Tiếp theo hãy cùng xem đoạn code sau đây để hiểu rõ hơn về Type Bound
class Animal class Dog extends Animal class Puppy extends Dog class AnimalCarer{ def display [T <: Dog](t: T){ println(t) } } object ScalaUpperBoundsTest { def main(args: Array[String]) { val animal = new Animal val dog = new Dog val puppy = new Puppy val animalCarer = new AnimalCarer //animalCarer.display(animal) animalCarer.display(dog) animalCarer.display(puppy) } }
Đoạn code trên hoạt động tốt khi chúng ta comment dòng code sau
//animalCarer.display(animal)
Nếu bỏ comment đoạn code này và thử chạy lại. Chúng ta sẽ gặp lỗi khi biên dịch. Bởi vì chúng ta định nghĩa Upper Bound như sau:
class AnimalCarer{ def display [T <: Dog](t: T){ println(t) } }
Ở đây chúng ta định nghĩa T <: Dog
điều này nghĩa là hàm display chỉ chấp nhận Object class của Dog hoặc kiểu subclass (ví dụ Puppy) của Dog class. Đây chính là lý do vì sao khi chúng ta truyền supper class của Dog (Animal), chúng ta sẽ gặp lỗi biên dịch “Type Mismatch”
Scala Lower Bounds
Trong Scala, chúng ta có thể định nghĩa Lower Bound trên Type Parameter như hình bên dưới đây:
Ở đây thì T là một Type Parameter và S là một Type. Bằng việc khái báo Lower Bound T >: S
nghĩa là Type Parameter hay T này phải giống với Type của S hoặc super-type của S
Ví dụ
[T >: Ordered[T]]
Ở đây chúng ta đã định nghĩa Lower Bound từ Type Parameter T đến Ordered[T]. Do đó T phải là Ordered hoặc super-type của Ordered.
Tiếp theo hãy cùng xem đoạn code sau đây để hiểu rõ hơn về Lower Bound
class Animal class Dog extends Animal class Puppy extends Animal class AnimalCarer{ def display [T >: Puppy](t: T){ println(t) } } object ScalaLowerBoundsTest { def main(args: Array[String]) { val animal = new Animal val dog = new Dog val puppy = new Puppy val animalCarer = new AnimalCarer animalCarer.display(animal) animalCarer.display(puppy) animalCarer.display(dog) } }
Ở đây thì Dog không phải là subtype của Puppy, nhưng đoạn code trên vẫn hoạt động tốt bởi vì Dog là subtype của Animal và chúng ta đã định nghĩa Lower Bound trên Type Parameter T như bên dưới đây
class AnimalCarer{ def display [T >: Puppy](t: T){ println(t) } }
Nếu chúng ta bỏ định nghĩa Lower Bound trong class này thì sẽ có một lỗi xảy ra khi biên dịch chương trình
Scala View Bounds
Trong Scala, View Bound thường được sử dụng khi chúng ta muốn sử dụng các chuyển đổi implicit hiện tại tự động. Chúng ta có thể định nghĩa View Bound trên Type Parameter như hình bên dưới đây:
Trong một vài trường hợp, chúng ta phải sử dụng chuyển đổi ngầm tự động để giải quyết vấn đề câu lệnh. Chúng ta có thể sử dụng View Bound để sử dụng những ngụ ý ngầm này.
Sau đây chúng ta sẽ thử viết một chương trình để so sánh các String với các toán tử quan hệ (như là Int 10 > 12).
class Person[T <% Ordered[T]](val firstName: T, val lastName: T) { def greater = if (firstName > lastName) firstName else lastName } object ScalaViewBoundsTest { def main(args: Array[String]) { val p1 = new Person("Rams","Posa") val p2 = new Person("Chintu","Charan") println(p1.greater) println(p2.greater) } }
Kết quả
Rams Chintu
Nếu chúng ta không sử dụng toán tử View Bound <%
thì chúng ta sẽ nhận được thông báo lỗi sau:
error: value > is not a member of type parameter T