2010-02-08 16 views
36

En Scala, he visto los constructosDiferencia entre la herencia rasgo y tipo auto anotación

trait T extends S 

y

trait T { this: S => 

utilizado para lograr cosas similares (es decir, que los métodos abstractos en S deben estar definido antes de que se pueda crear una instancia). ¿Cual es la diferencia entre ellos? ¿Por qué usarías uno sobre el otro?

+9

duplicado exacto de http://stackoverflow.com/questions/1990948/what-is-the-difference-between-scala-self-types-and-trait-subclasses, que es la primera pregunta que aparece en la lista relacionada . –

Respuesta

12

Usaría auto-tipos para la administración de dependencias: esta característica requiere que se mezcle otro rasgo. Y usaría la herencia para refinar otra característica o interfaz.

Sólo como ejemplo:

trait FooService 

trait FooRemoting { this : FooService => } 
trait FooPersistence { this : FooService => } 

object Services extends FooService with FooRemoting with FooPersistence 

Ahora, si FooRemoting y FooPersistence tanto habrían heredado de FooService y FooService tiene miembros y métodos, ¿cómo Servicios parecerse?

Mientras que para la herencia, tendríamos algo como:

trait Iterator[T] { 
    def hasNext : boolean 
    def next : T 
} 

trait InfiniteIterator[T] extends Iterator[T] { 
    def hasNext = true 
} 
+16

Lo siento, Victor, no entiendo el "¿cómo se verían los servicios?" parte. Intenté en ambos sentidos y puedo ver que el objeto Servicios se comporta de la misma manera. ¿Cuál es la situación que hace la diferencia aparente? – ithkuil

25

tipo auto anotaciones le permiten expresar dependencias cíclicas. Por ejemplo:

trait A extends B 
trait B { self: A => } 

Esto no es posible con la herencia simple.

+0

¿tiene casos de uso? – crak

+0

Puede usar esta técnica para imitar las clases parciales que se encuentran en C#. Consulte https://msdn.microsoft.com/en-us/library/wa80x488.aspx, por ejemplo. –

6

Dado que la pregunta me encontré con estos mensajes:

Spiros Tzavellas habla sobre el uso de un rasgo como la interfaz pública y el tipo de auto como un ayudante que debe ser mezclado en la clase de implementación.

En conclusión, si queremos mover implementaciones de métodos dentro de los rasgos entonces corremos el riesgo de contaminar la interfaz de esos rasgos con los métodos abstractos que apoyan la aplicación de las métodos concretos y no están relacionados con los principales responsabilidad del rasgo . Una solución a este problema es para mover esos métodos abstractos en otros rasgos y componer los rasgos usando las anotaciones de tipo propio y la herencia múltiple.

Por ejemplo:

trait PublicInterface { this: HelperTrait => 
    // Uses helperMethod 
} 

trait HelperTrait { 
    def helperMethod = // ... 
} 

class ImplementationClass extends PublicInterface with HelperTrait 

A Tour of Scala explica el uso de anotaciones de tipo auto con los miembros de tipo abstracto - es de suponer que no es posible extend un miembro de tipo abstracto

+0

que está al revés, ¿no? Debería ser "clase ImplementationClass extends HelperTrait with PublicInterface"; es decir, un rasgo se debe mezclar primero antes de hacer referencia a él como un tipo propio – virtualeyes

+0

Esto me parece un mal diseño. Los métodos de ayuda son una preocupación de implementación de subclases de 'PublicInterface'. ¿Por qué no usar métodos 'protected'? –

1

A pesar de que no lo hace la respuesta (?) su pregunta, estaba tratando de entender las anotaciones de tipo propio y básicamente me perdí en las respuestas, y de alguna manera terminé yendo en bicicleta a través de las variaciones de su pregunta, que se centra en el uso de anotaciones de tipo propio para establecer dependencias.

Así Aquí dejo una descripción de un caso de uso, donde las anotaciones de tipo auto están bien ilustradas, es decir, algo así como un caso de tipo seguro de 'esto' como un subtipo:

http://programming-scala.labs.oreilly.com/ch13.html#SelfTypeAnnotationsAndAbstractTypeMembers

la esperanza de que sería de gran ayuda para aquellos que terminan en esta pregunta por casualidad (y, como yo, no tiene tiempo para leer un libro Scala antes de comenzar a explorar :-))

+0

Han cambiado los enlaces. Ahora es: http://ofps.oreilly.com/titles/9780596155957/ApplicationDesign.html (en "Anotaciones de tipo propio y miembros de tipo abstracto"; sin enlace directo) – akauppi

2

La respuesta es "circularidad". Pero no solo.

La anotación del tipo de auto resuelve para mí el problema fundamental de la herencia: lo que heredas no puede usar lo que eres. Con el tipo de auto, todo se vuelve fácil.

Mi patrón es el siguiente y se puede considerar como una torta degenerado:

trait A { self: X => def a = reuseme} 
trait B { self: X => def b = a } 
class X extends A with B { def reuseme=null } 

Puede explotar su clase en múltiples comportamientos que pueden ser llamadas desde cualquier parte del montaje, mientras que permanece limpiamente mecanografiado. No es necesaria la indirecta dolorosa con demasiada frecuencia (e incorrectamente) identificada con el patrón de tortas.

La mitad (si no la totalidad) de los intrincados marcos de Java DI de los últimos diez años se han dedicado a hacer esto, por supuesto, sin el tipeo. Las personas que todavía usan JAVA en este dominio están perdiendo el tiempo: "SCALA ouakbar".

Cuestiones relacionadas