2012-02-08 24 views
7

Nói rằng tôi có một loại kinded caokìm hãm các loại-Kinded cao hơn trong Scala

SuperMap[Key[_],Value[_]]`. 

Giả sử bây giờ mà tôi có một cái gì đó thậm chí cụ thể hơn đòi hỏi rằng các tham số kiểu cho Key phải phù hợp mà cho Value; có nghĩa là, một cái gì đó như:

SuperDuperMap[T, Key[T], Value[T]] 

Hơn nữa giả sử rằng tôi không muốn chỉ cần bất kỳ T, nhưng rất cụ thể một trong những nơi T <: OtherT

SuperDuperPooperMap[T <: OtherT, Key[T], Value[T]] 

này có thể được thực hiện trong Scala? Đây có phải chỉ là một ý tưởng tồi? Có cách tương đương để làm điều này dễ đọc/ghi/sử dụng hơn không?

Trả lời

11

Tuyên bố của bạn đã hoạt động như nghĩa vụ, nghĩa là bạn đang hạn chế loại T cũng như KeyValue. Cách bạn đã viết nó, tuy nhiên, scala sẽ phàn nàn nếu bạn phát hành cái gì đó như

scala> class Foo[T <: OtherT, Key[T], Value[T]] 
defined class Foo 

scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]] 
<console>:13: error: Key[SpecialOtherT] takes no type parameters, expected: one 
       new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]] 

vì các loại của cả hai KeyValue đã trao bằng tuyên bố cựu của bạn. Do đó, thao tác này sẽ hoạt động

scala> new Foo[SpecialOtherT, Key, Value] 
res20: Foo[SpecialOtherT,Key,Value] = [email protected] 

có thể không muốn bạn muốn. Bạn có thể làm điều đó như thế này

scala> class Foo[T <: OtherT, K <: Key[T], V <: Value[T]] 
defined class Foo 

scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]] 
res21: Foo[SpecialOtherT,Key[SpecialOtherT],Value[SpecialOtherT]] = [email protected] 

Tại dòng dưới cùng, vì các loại KeyValue phụ thuộc hoàn toàn vào T nó là hơi thừa để có tất cả các thông tin cần thiết khi làm việc với Foo.Vậy tại sao không sử dụng một tuyên bố loại bên trong như vậy:

class Foo[T <: OtherT] { 
    type K = Key[T] 
    type V = Value[T] 
} 

Sau đó, bạn sẽ có quyền truy cập đến các loại KV từ bên trong lớp nhưng sẽ không cần phải gõ nó mỗi khi bạn tạo ra một câu trả lời mới:

scala> new Foo[SpecialOtherT] 
res23: Foo[SpecialOtherT] = [email protected] 

scala> new Foo[Int] 
<console>:11: error: ... 
+0

Cảm ơn! Rất thông tin. Câu trả lời duy nhất của tôi cho "Vì vậy, tại sao không sử dụng một tuyên bố kiểu bên trong" là tôi muốn có những loại đó cho K và V suy luận về sự khởi tạo. – duckworthd

+0

Tôi không chắc tôi hiểu vì loại thực sự được phỏng đoán. Tùy thuộc vào trường hợp sử dụng của bạn, bạn vẫn có thể sử dụng loại từ "bên ngoài", ví dụ: 'class Foo [T]; lớp Bar [T] {loại Wee = Foo [T]}; def doSomething [T] (b: Bar [T]) (ngầm định mf: Manifest [Bar [T] #Wee]) {Console println mf} ', và sau đó' doSomething (new Bar [Double]) '. Đồng ý, đó là một ví dụ bẩn. – fotNelton

3

Điều này có thể thực hiện được ở Scala không?

Ý của bạn là gì? Bạn đã làm!

Đây có phải chỉ là ý tưởng tồi không?

Tại sao lại như vậy? Trong thực tế đó là một ý tưởng tuyệt vời! Đây là những loại cao cấp dành cho.

Có cách tương đương để thực hiện việc này dễ đọc/ghi/sử dụng hơn không?

Đọc số - đọc khá tốt với tôi.

Viết - ghi/thử/biên dịch một lần, sử dụng ở mọi nơi.

Sử dụng - Trình biên dịch sẽ tạo lại (suy ra) các loại "ở khắp mọi nơi".

+0

Khi mã của tôi biên dịch, nó không thể được khởi tạo: X – duckworthd

2

Bạn có lẽ không cần bất cứ điều gì phức tạp hơn một vài loại bí danh,

type SuperDuperMap[T, Key[_], Value[_]] = SuperMap[Key, Value] 

type SuperDuperPooperMap[T <: OtherT, Key[_], Value[_]] = SuperMap[Key, Value] 

mẫu phiên REPL,

scala> new SuperDuperMap[Int, Option, List] {} 
res0: java.lang.Object with SuperDuperMap[Int,Option,List] = ... 

scala> new SuperDuperPooperMap[OtherT, Option, List] {} 
res1: java.lang.Object with SuperDuperPooperMap[OtherT,Option,List] = ... 
Các vấn đề liên quan