2012-02-08 8 views
7

dire che ho un tipo kinded superioredi vincoli ai tipi superiori-Kinded a Scala

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

Supponiamo ora che ho avuto qualcosa di ancora più specifico che ha richiesto che il parametro tipo per Key deve corrispondere a quello per Value; vale a dire, qualcosa come:

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

Ulteriori Suppongo che non volevo solo qualsiasi T, ma uno molto specifico in cui T <: OtherT

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

si può fare a Scala? Questa è solo una cattiva idea? Esiste un modo equivalente per fare ciò che è più facile da leggere/scrivere/utilizzare?

risposta

11

La tua dichiarazione funziona già come previsto, ovvero stai limitando il tipo di T e Key e Value. Il modo in cui hai scritto, tuttavia, scala si lamenterà se si emette qualcosa come

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]] 

perché i tipi di entrambi Key e Value sono già date dal vostro precedente dichiarazione. Quindi funzionerà

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

che probabilmente non si desidera si desideri. Si potrebbe fare come questo

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] 

In linea di fondo, dal momento che i tipi di Key e Value dipendono esclusivamente T è un po 'superfluo avere tutte le informazioni ridondanti quando si lavora con Foo.Allora perché non utilizzare una dichiarazione di tipo interna in questo modo:

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

Poi si avrebbe accesso a tipi K e V dall'interno della classe, ma non avrebbe bisogno di digitare ogni volta che si crea una nuova risposta:

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

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

Grazie! Molto informativo. La mia unica risposta a "Allora, perché non usare una dichiarazione di tipo interno" è che voglio avere quei tipi per K e V dedotti in istanziazione. – duckworthd

+0

Non sono sicuro di aver capito perché il tipo in realtà viene dedotto. A seconda del caso d'uso, puoi comunque utilizzare il tipo dal "fuori", ad es. 'classe Foo [T]; class Bar [T] {type Wee = Foo [T]}; def doSomething [T] (b: Bar [T]) (implicito mf: Manifest [Bar [T] #Wee]) {Console println mf} ', quindi' doSomething (new Bar [Double]) '. D'accordo, è un esempio sporco. – fotNelton

3

Questo può essere fatto in Scala?

Cosa intendi? Lo hai appena fatto!

Questa è solo una cattiva idea?

Perché dovrebbe essere? In effetti è un'ottima idea! Questo è ciò per cui sono destinati i tipi più elevati.

Esiste un modo equivalente per farlo più semplice da leggere/scrivere/utilizzare?

Lettura - si legge molto bene con me.

Scrivere - scrivere/testare/compilare una volta, utilizzare ovunque.

Utilizzo di - Il compilatore ricostruirà (dedotto) i tipi "ovunque".

+0

Mentre il mio codice viene compilato, non può essere istanziato: X – duckworthd

2

probabilmente non avete bisogno di qualcosa di più complicato di un paio di tipo alias,

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

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

di campionamento della sessione 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] = ... 
Problemi correlati