2010-07-02 34 views
7

Qual è la differenza tra i due seguenti?Una domanda sui tratti

1 #

trait B extends A { 

} 

2 #

trait B { self: A => 

} 

dove A è una classe astratta.

> > EDIT:

Si prega di spiegare per quanto riguarda il seguente esempio di Duck s con volare pluggable e comportamenti quacking:

abstract class Duck { 
    def fly(): Unit 
    def quack(): Unit 
    def swim() { 
    println("Woodoowoodoowoodoo...") 
    } 
} 

trait FlyingWithWings extends Duck { 
    override def fly() { 
    println("Me can fliez! :D") 
    } 
} 

trait FlyingNoWay { self: Duck => 
    def fly() { 
    println("Me cannot fliez! :(") 
    } 
} 

trait Quack extends Duck { 
    override def quack() { 
    println("Quack! Quack!") 
    } 
} 

trait MuteQuack { self: Duck => 
    def quack() { 
    println("<<Silence>>") 
    } 
} 

class MallardDuck extends Duck with FlyingWithWings with MuteQuack 

object Main { 
    def main(args: Array[String]) { 
    val duck = new MallardDuck 
    duck.fly() 
    duck.quack() 
    } 
} 

uscita:

Me può fliez! : D
< < Silenzio >>

+4

Cerca un duplicato di http://stackoverflow.com/questions/2224932/difference-tra between-traheritance-and-self-type-annotation, a sua volta un duplicato di http://stackoverflow.com/questions/1990948/what-is-the-difference-between-scala-self-types-and-trait-sottoclasse – VonC

risposta

5

Nel secondo caso B non può essere utilizzato in luoghi in cui è prevista una A, è solo progettato per essere "collegato" ad una determinata A. Quindi, ad esempio, nel primo caso A potrebbe essere astratto e B potrebbe implementare i metodi mancanti, rendendolo un tipo istantaneo. Questo non è possibile nel secondo caso, è necessario un "A completo", e solo allora si aggiunge una funzionalità.

Quindi si potrebbe pensare ad una relazione "si adatta in un ..." invece che a "è un ...".

+0

Quale dovrebbe essere preferito? E perché? –

+0

Dipende se estendi davvero il tratto base o no. Per esempio. se hai un grafico tratto, un nuovo tratto ColorGraph chiaramente "è un" (nuovo tipo di) grafico e dovrebbe estendere il tratto base. D'altra parte se aggiungi un tratto con un metodo findCycles, questo tratto ha senso solo se usato insieme a Graphs, ma non crea un nuovo tipo di grafico, aggiunge solo alcune funzionalità, quindi scegli la seconda versione con il tipo di auto in questo caso. In alcuni casi le differenze non sono così chiare, ma con un po 'di esperienza vedrai quale versione si adatta meglio al tuo progetto. – Landei

+0

Non penso che tu mi abbia preso. Fammi provare a riformulare. Nella mia domanda, 'A' è una' classe astratta', non una 'caratteristica'. Nell'esempio che ho incluso, è possibile collegare (o integrare) i comportamenti in entrambi i modi. ('FlyingWithWings' usa l'estensione mentre' MuteQuack' usa l'annotazione di tipo self.) Quindi, quando dovrei preferire un modo piuttosto che un altro e perché? –

1

Nel primo esempio B è una specializzazione di A. Il secondo significa che il tratto B deve sempre essere mixato in qualcosa che è, o è un sottotipo di, A (che può essere una classe, un tratto o qualsiasi altro tipo).

+2

Nessun tratto può estendere anche una classe – Aymen

+0

Non lo sapevo, ma l'ho provato nel REPL e funziona . Non puoi ancora avere più di una classe nella discendenza diretta, però, quindi non puoi avere ereditarietà multipla (ecco perché non potrei avere tratti che estendono le classi). – Theo