2010-07-02 17 views
7

¿Cuál es la diferencia entre los dos siguientes?Una pregunta sobre los rasgos

1 #

trait B extends A { 

} 

2 #

trait B { self: A => 

} 

donde A es una clase abstracta.

> > EDIT:

Por favor, explique con respecto al siguiente ejemplo de Duck s con el vuelo enchufable y comportamientos 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() 
    } 
} 

Salida:

me puedo fliez! : D
< < Silencio >>

+4

Mira un duplicado de http://stackoverflow.com/questions/2224932/difference-between-trait-inheritance-and-self-type-annotation, en sí mismo un duplicado de http://stackoverflow.com/questions/1990948/what-is-the-difference-between-scala-self-types-and-trait-subclasses – VonC

Respuesta

5

En el segundo caso, B no se puede usar en lugares donde se espera una A, simplemente está diseñado para ser "conectado" a una A determinada. Por ejemplo, en el primer caso A podría ser abstracto y B podría implementar los métodos faltantes, convirtiéndolo en un tipo instanciable. Esto no es posible en el segundo caso, necesita una "A completa", y solo luego agrega alguna funcionalidad.

Así que podría pensar en una relación "encaja en ..." en lugar de una relación "es un ...".

+0

¿Cuál debería ser el preferido? ¿Y por qué? –

+0

Depende si realmente extiende el rasgo base o no. P.ej. si tiene un Trait Graph, un rasgo nuevo de ColoredGraph claramente "es un" (nuevo tipo de) gráfico y debería extender el rasgo base. Por otro lado, si agrega un rasgo con un método findCycles, este rasgo solo tiene sentido cuando se usa junto con Graphs, pero no crea un nuevo tipo de Graph, solo agrega alguna funcionalidad, por lo que elegiría la segunda versión con el tipo de self en este caso. En algunos casos, las diferencias no son tan claras, pero con algo de experiencia, verá qué versión se adapta mejor a su diseño. – Landei

+0

No creo que me hayas atrapado. Déjame intentar reformular. En mi pregunta, 'A' es una' clase abstracta', no un 'rasgo'. En el ejemplo que he incluido, es posible conectar (o mezclar) los comportamientos de ambas maneras. ('FlyingWithWings' usa la extensión, mientras que' MuteQuack' utiliza la anotación de tipo propio.) Entonces, ¿cuándo debería preferir una forma sobre otra y por qué? –

1

En el primer ejemplo B es una especialización de A. El segundo significa que el rasgo B siempre debe mezclarse en algo que sea, o sea un subtipo de, A (que puede ser una clase, rasgo o cualquier otro tipo).

+2

Ningún rasgo puede extender una clase también – Aymen

+0

No lo sabía, pero lo probé en REPL y funciona . Sin embargo, todavía no puedes tener más de una clase en el ancestro directo, por lo que no puedes obtener herencia múltiple (por lo que pensé que no podrías tener rasgos que extendieran las clases). – Theo