2012-08-07 14 views
11

Voglio utilizzare un tipo astratto piuttosto che un parametro di tipo.costruttori di scala di scala e tipi astratti

Nel mio costruttore classi generiche, voglio avere un parametro di tipo generico, ma il codice non compilazione:

class SomeOtherClass(val s: S){ 
    type S 
} 

L'errore scala compilatore è "non trovato: tipo S"

Se uso un parametro di tipo, invece di un tipo astratto, allora funziona:

class SomeClass[T](val t: T){ 
    //... 
} 

costringe Scala me di utilizzare un parametro di tipo piuttosto che un tipo astratto, se voglio avere un parametro generico nel costruttore?

C'è un altro modo per farlo?

risposta

3

In questo caso, è praticamente necessario utilizzare parametri di tipo generico. Puoi aggirare il problema dichiarando il tipo al di fuori della classe, ma poi dovresti istanziare il wrapper e quindi l'oggetto e diventerebbe brutto abbastanza rapidamente.

trait FooDef { 
    type T 
    class Foo(val x: T) 
} 
val ifd = new FooDef { type T = Int } 
val ifoo = new ifd.Foo(5) 
val sfd = new FooDef { type T = String } 
val sfoo = new sfd.Foo("hi") 
def intFoos(f: fd.Foo forSome { val fd: FooDef {type T = Int} }) = f.x + 1 
0

Come dovrebbe sapere il compilatore che tipo dovrebbe utilizzare lì? O devi specificare direttamente il tipo, che non avrebbe molto senso, o usare un generico. C'è un modo per farlo funzionare, ma non penso che ti possa aiutare.

class SomeClass(s: SomeClass#S) { 
    type S 
} 

Ma come SomeClass # S non è definito, non esiste un'istanza di esso.

+0

Abbastanza divertente questo vi permetterà di creare istanze 'new SomeClass (5.asInstanceOf [SomeClass # S]) {type S = Int}'. Nota che non c'è sicurezza, S è ancora indefinito nel cast. – Kaito

+0

Quindi, fondamentalmente per farlo bene, devo guardare le altre due risposte? –

+0

@AntKutschera sì. – Nicolas

0

Forse vuoi qualcosa del genere? In questo modo è possibile avere più istanze di AbstractFooFactory ciascuna producendo s con un valore diverso per s.

trait AbstractFooFactory { 
    type S 
    def makeFoo(s:S):Foo 
    class Foo(val s:S) {} 
} 

object StringFooFactory extends AbstractFooFactory { 
    override type S = String 
    override def makeFoo(s:String) = new Foo(s) 
} 

val b = StringFooFactory.makeFoo("bar") 
val s:String = b.s 
1

Quando il tipo astratto non è specificato, la classe deve essere astratta. Quindi non hai affatto bisogno del parametro. L'equivalente di un tipo astratto sarebbe:

abstract class SomeOtherClass { 
    type S 
    val s: S 
} 

Poi a uso loco:

val x = new SomeOtherClass { 
    type S = String 
    val s = "abc" 
} 

Senza il parametro, la classe astratta qui è equivalente a un tratto. È meglio usare un tratto perché è meno restrittivo (puoi estendere solo una classe base).