tôi có các mô hình:loại Giải quyết trong F-giáp đa hình
trait Vehicle[T <: Vehicle[T]] { def update(): T }
class Car extends Vehicle[Car] { def update() = new Car() }
class Bus extends Vehicle[Bus] { def update() = new Bus() }
Nếu tôi có được một thể hiện của một Vehicle[Car]
và gọi update()
, tôi sẽ nhận được một Car
. Kể từ Car
kéo dài Vehicle[Car]
(hoặc chỉ cần đặt, Xe là một xe [Xe]), tôi có thể yên tâm đặt kiểu của kết quả một cách rõ ràng để Vehicle[Car]
:
val car = new Car
val anotherCar = car.update()
val anotherCarAsVehicle: Vehicle[Car] = car.update() // works as expected
Nhưng nếu tôi muốn, nói, đặt trường hợp của Car
và Bus
lại với nhau thành một danh sách, sau đó tôi phải thiết lập các loại danh sách để Vehicle[_ <: Vehicle[_]]
(có một danh sách đơn giản Vehicle[_]
và gọi update()
trên một yếu tố sẽ mang lại Any
, nhưng tôi muốn để có thể sử dụng update()
vì vậy tôi phải sử dụng loại F-bounded). Sử dụng các loại hiện sinh vít lên các mối quan hệ chủng loại, bởi vì một khi tôi lấy chiếc xe cơ bản/xe buýt từ xe, tôi không còn có thể bỏ nó vào xe vì ... tốt, nó chỉ là một số loại hiện sinh:
val seq = List[Vehicle[_ <: Vehicle[_]]](new Car, new Bus)
val car = seq.head.update()
val carAsVehicle: Vehicle[_ <: Vehicle[_]] = seq.head.update() // fails to compile
Vì vậy, , Vehicle
được tham số hóa với một số loại T
là loại phụ của Vehicle[T]
. Khi tôi tách ra các T
(bằng cách sử dụng update()
), trong trường hợp các loại cụ thể thì không sao - ví dụ: nếu tôi trích xuất số Car
, tôi có thể an toàn xác nhận rằng tôi đã tách ra Vehicle[Car]
vì Car <: Vehicle[Car]
. Nhưng nếu tôi tách ra một loại tồn tại, tôi không thể làm bất cứ điều gì với nó. Ví dụ trước đây hoạt động vì Car
là Vehicle[Car]
, nhưng trong trường hợp này _
không phải là Vehicle[_]
.
Để chỉ định câu hỏi cụ thể của tôi: cho các mô hình được nêu ở trên (Xe hơi, Xe hơi, Xe buýt), có cách nào để đạt được điều này không?
def sameType[T, U](a: T, b: U)(implicit evidence: T =:= U) = true
val seq = List[Vehicle[_ <: Vehicle[_]]](new Car, new Bus)
sameType(seq.head.update +: seq.tail, seq) // true
Lưu ý rằng bạn có thể thay đổi các đặc điểm, các lớp học nhất định và loại seq
, nhưng có một hạn chế: update()
phải trả lại T
, không Vehicle[T]
.
Tôi biết rằng sử dụng shapeless HList
sẽ giải quyết vấn đề vì tôi sẽ không phải sử dụng các loại hiện có (tôi chỉ đơn giản là có danh sách xe hơi và xe buýt, và thông tin kiểu đó sẽ được giữ nguyên). Nhưng tôi tự hỏi cho trường hợp sử dụng cụ thể này với một đơn giản List
.
EDIT:
@RomKazanova có, mà sẽ làm việc tất nhiên, nhưng tôi cần phải giữ lại cùng loại trước và sau khi update()
(đây là một phiếu bầu tán thành cho các nỗ lực mặc dù;)).
Tôi tin rằng không thể không có HList hoặc cấu trúc dữ liệu tương tự, vì xe ô tô và xe buýt thống nhất buộc chúng tôi sử dụng loại xe mất thông tin về loại cơ bản của nó là Xe hơi, Xe buýt hay gì đó khác (tất cả những gì chúng ta có thể biết là rằng đó là một số loại _ <: Vehicle
). Nhưng tôi muốn kiểm tra với các bạn.
Tôi đã có thể nghĩ rằng 'Danh sách [Xe [_ <: Xe [_]]]' là loại giống như 'Danh sách [Xe [ T] forSome {type T <: Xe [T]}] '. Như một quy tắc chung của ngón tay cái tôi sẽ không nhớ sử dụng 'forSome' ở khắp mọi nơi, nhưng tôi nghe nói nó đang bị đuổi ra khỏi Scala 2.13 hoặc 2.14. Dù sao, cảm ơn bạn rất nhiều, đây chính là loại giải pháp mà tôi đã hy vọng. – slouc
Tôi đã loại bỏ tất cả các cảnh báo kiểu tồn tại từ bảng điểm REPL của tôi. Vì vậy, tôi nghĩ đây là loại tồn tại không thể giải thích được với các ký tự đại diện duy nhất. Tôi không chắc chắn * nếu * nó sẽ được gỡ bỏ hoàn toàn, nhưng nếu có thì tôi * nghĩ * sớm nhất sẽ là khi Dotty trở thành Scala 3.0 hoặc một cái gì đó như thế. –
BTW Tôi vô tình downvoted bạn :) cố định – slouc