Bạn sẽ không nói về 'ghi đè' đối với các loại, nhưng thay vì thu hẹp giới hạn của chúng.
type T
... không giới hạn
type T <: C
... T
là C
hoặc một subtype của C
(được gọi là trên ràng buộc)
type T >: C
... T
là C
hoặc một supertype của C
(được gọi là giới hạn dưới)
type T = C
... T
là chính xác C
(loại bí danh)
Do đó, nếu T
là thành viên loại đặc điểm A
, và SubA
là một subtype của A
, trong trường hợp (2) SubA
có thể thu hẹp T
đến một subtype đặc biệt hơn C
, trong khi đó (3) nó có thể thu hẹp nó thành một siêu kiểu cao hơn là C
. Trường hợp (1) không áp đặt bất kỳ hạn chế nào đối với SubA
, trong khi trường hợp (4) có nghĩa là T
là 'cuối cùng' để nói.
này có hậu quả đối với các useability của T
trong A
-liệu nó có thể xuất hiện như kiểu một đối số phương pháp hay kiểu trả về của phương pháp.
Ví dụ:
trait C { def foo =() }
trait SubC extends C { def bar =() }
trait MayNarrow1 {
type T <: C // allows contravariant positions in MayNarrow1
def m(t: T): Unit = t.foo // ...like this
}
object Narrowed1 extends MayNarrow1 {
type T = SubC
}
object Narrowed2 extends MayNarrow1 {
type T = SubC
override def m(t: T): Unit = t.bar
}
Có thể xác định phương pháp m
trong MayNarrow1
vì loại T
xảy ra trong vị trí contravariant (as type một cuộc tranh luận phương pháp của), do đó nó vẫn còn hiệu lực ngay cả khi T
được thu hẹp xuống trong một loại phụ của MayNarrow1
(thân phương pháp có thể xử lý t
như thể nó là loại C
).
Ngược lại, type T = C
không tránh khỏi sửa lỗi T
, loại tương ứng với phương thức thực hiện final
.Bằng cách sửa chữa T
, nó có thể được sử dụng trong một vị trí hiệp biến (như kiểu trả về của phương pháp):
trait Fixed extends MayNarrow1 {
type T = C // make that T <: C to see that it won't compile
final def test: T = new C {}
}
Bạn có thể dễ dàng thấy rằng nó phải được cấm để tiếp tục 'đè' T
:
trait Impossible extends Fixed {
override type T = SubC
test.bar // oops...
}
Để được hoàn thành, đây là trường hợp ít phổ biến của một ràng buộc thấp:
trait MayNarrow2 {
type T >: SubC // allows covariant positions in MayNarrow2
def test: T = new SubC {}
}
object Narrowed3 extends MayNarrow2 {
type T = C
test.foo
}
object Narrowed4 extends MayNarrow2 {
type T = C
override def test: T = new C {}
}
Lưu ý: cho sự khác biệt tinh tế giữa các thành viên kiểu trừu tượng với giới hạn so với các tham số kiểu với chú thích phương sai, xem bài đăng của Geoffrey Washburn trong http://scala-programming-language.1934581.n4.nabble.com/Scala-type-override-td1943353 .html –