2017-02-24 13 views
5

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 CarBus 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]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ì CarVehicle[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.

Trả lời

4

Tôi không phải là rất tốt với các loại hiện sinh , vì vậy tôi không thể giải thích quá nhiều về điều này :-p Nhưng khi bạn thay đổi loại seq thành List[Vehicle[T] forSome {type T <: Vehicle[T]}] mọi thứ dường như "làm việc". Tâm trí bạn phải chuyển loại sang phương thức khởi tạo/áp dụng List.

scala> val seq = List[Vehicle[T] forSome {type T <: Vehicle[T]}](new Car, new Bus) 
seq: List[Vehicle[T] forSome { type T <: Vehicle[T] }] = List([email protected], [email protected]) 

scala> sameType(seq.head.update +: seq.tail, seq) 
res3: Boolean = true 

scala> seq.head.update 
res4: T forSome { type T <: Vehicle[T] } = [email protected] 

scala> seq.head.update.update 
res5: T forSome { type T <: Vehicle[T] } = [email protected] 

scala> new Car +: seq 
res6: List[Vehicle[T] forSome { type T <: Vehicle[T] }] = List([email protected], [email protected], [email protected]) 

Tôi nghĩ rằng điều chủ yếu để có được ra khỏi câu trả lời này là điều này cho phép bạn giải thích rõ ràng bản chất đệ quy của các nhà xây dựng Vehicle loại.

Tôi không chắc chắn tôi sẽ khuyên này mặc dù ...

+0

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

+0

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ế. –

+0

BTW Tôi vô tình downvoted bạn :) cố định – slouc

2

Có hai cách để giải quyết nó:

val carAsVehicle: Vehicle[_] = seq.head.update() 

hoặc sử dụng mô hình kết hợp

val carAsVehicle: Vehicle[Car] = seq.head match { 
    case car: Vehicle[Car] => car.update() 
} 

Nhưng thú vị rằng:

val seq = List[Vehicle[_ <: Vehicle[_]]](new Car, new Bus) 

val vehicleAsVihecles: List[Vehicle[_]]= seq.map(_.update()) // compiled 

val vehicleAsVihecles1: List[Vehicle[_ <: Vehicle[_]]]= seq.map(_.update()) //not compiled 

def somedef(vehicles: List[Vehicle[_ <: Vehicle[_]]]) = vehicles.map(_.update()) //compiled 
somedef(seq) 
Các vấn đề liên quan