Scala Language
Rasgos
Buscar..
Sintaxis
- rasgo ATrait {...}
- clase AClass (...) extiende ATrait {...}
- clase AClass extiende BClass con ATrait
- clase AClass extiende ATrait con BTrait
- La clase AClass extiende ATrait con BTrait con CTrait.
- clase ATrait extiende BTrait
Modificación apilable con rasgos
Puede usar rasgos para modificar los métodos de una clase, usando rasgos en forma apilable.
El siguiente ejemplo muestra cómo se pueden apilar los rasgos. El ordenamiento de los rasgos es importante. Usando diferentes orden de rasgos, se logra un comportamiento diferente.
class Ball {
def roll(ball : String) = println("Rolling : " + ball)
}
trait Red extends Ball {
override def roll(ball : String) = super.roll("Red-" + ball)
}
trait Green extends Ball {
override def roll(ball : String) = super.roll("Green-" + ball)
}
trait Shiny extends Ball {
override def roll(ball : String) = super.roll("Shiny-" + ball)
}
object Balls {
def main(args: Array[String]) {
val ball1 = new Ball with Shiny with Red
ball1.roll("Ball-1") // Rolling : Shiny-Red-Ball-1
val ball2 = new Ball with Green with Shiny
ball2.roll("Ball-2") // Rolling : Green-Shiny-Ball-2
}
}
Tenga en cuenta que super
se utiliza para invocar el método roll()
en ambos rasgos. Solo así podremos lograr una modificación apilable. En casos de modificación apilable, el orden de invocación del método está determinado por la regla de linealización .
Fundamentos del rasgo
Esta es la versión más básica de un rasgo en Scala.
trait Identifiable {
def getIdentifier: String
def printIndentification(): Unit = println(getIdentifier)
}
case class Puppy(id: String, name: String) extends Identifiable {
def getIdentifier: String = s"$name has id $id"
}
Dado que no se declara ninguna AnyRef
para el carácter Identifiable
, por defecto se extiende desde la clase AnyRef
. Debido a que no se proporciona una definición para getIdentifier
en Identifiable
, la clase Puppy
debe implementarla. Sin embargo, Puppy
hereda la implementación de printIdentification
de Identifiable
.
En el REPL:
val p = new Puppy("K9", "Rex")
p.getIdentifier // res0: String = Rex has id K9
p.printIndentification() // Rex has id K9
Resolviendo el problema del diamante
El problema de diamante , o herencia múltiple, es manejado por Scala usando Rasgos, que son similares a las interfaces de Java. Los rasgos son más flexibles que las interfaces y pueden incluir métodos implementados. Esto hace rasgos similares a mixins en otros idiomas.
Scala no admite la herencia de varias clases, pero un usuario puede extender múltiples rasgos en una sola clase:
trait traitA {
def name = println("This is the 'grandparent' trait.")
}
trait traitB extends traitA {
override def name = {
println("B is a child of A.")
super.name
}
}
trait traitC extends traitA {
override def name = {
println("C is a child of A.")
super.name
}
}
object grandChild extends traitB with traitC
grandChild.name
Aquí grandChild
se hereda de traitB
y traitC
, que a su vez heredan de traitA
. La salida (a continuación) también muestra el orden de prioridad al resolver qué implementaciones de métodos se llaman primero:
C is a child of A.
B is a child of A.
This is the 'grandparent' trait.
Tenga en cuenta que, cuando se utiliza super
para invocar métodos en class
o trait
, la regla de linealización entra en juego para decidir la jerarquía de llamadas. El orden de linealización para grandChild
será:
grandChild -> traitC -> traitB -> traitA -> AnyRef -> Any
A continuación se muestra otro ejemplo:
trait Printer {
def print(msg : String) = println (msg)
}
trait DelimitWithHyphen extends Printer {
override def print(msg : String) {
println("-------------")
super.print(msg)
}
}
trait DelimitWithStar extends Printer {
override def print(msg : String) {
println("*************")
super.print(msg)
}
}
class CustomPrinter extends Printer with DelimitWithHyphen with DelimitWithStar
object TestPrinter{
def main(args: Array[String]) {
new CustomPrinter().print("Hello World!")
}
}
Este programa imprime:
*************
-------------
Hello World!
La linealización para CustomPrinter
será:
CustomPrinter -> DelimitWithStar -> DelimitWithHyphen -> Printer -> AnyRef -> Any
Linealización
En caso de modificación apilable , Scala organiza clases y rasgos en un orden lineal para determinar la jerarquía de llamadas a métodos, lo que se conoce como linealización . La regla de linealización se usa solo para aquellos métodos que involucran la invocación de métodos a través de super()
. Consideremos esto con un ejemplo:
class Shape {
def paint (shape: String): Unit = {
println(shape)
}
}
trait Color extends Shape {
abstract override def paint (shape : String) {
super.paint(shape + "Color ")
}
}
trait Blue extends Color {
abstract override def paint (shape : String) {
super.paint(shape + "with Blue ")
}
}
trait Border extends Shape {
abstract override def paint (shape : String) {
super.paint(shape + "Border ")
}
}
trait Dotted extends Border {
abstract override def paint (shape : String) {
super.paint(shape + "with Dotted ")
}
}
class MyShape extends Shape with Dotted with Blue {
override def paint (shape : String) {
super.paint(shape)
}
}
La linealización pasa de atrás hacia delante . En este caso,
La primera
Shape
será linealizada, lo que se parece a:Shape -> AnyRef -> Any
Entonces
Dotted
se linealiza:Dotted -> Border -> Shape -> AnyRef -> Any
El siguiente en la línea es
Blue
. Normalmente la linealización delBlue
será:Blue -> Color -> Shape -> AnyRef -> Any
porque, en la linealización de
MyShape
hasta ahora ( Paso 2 ),Shape -> AnyRef -> Any
ya ha aparecido. Por lo tanto, se ignora. Así, la linealizaciónBlue
será:Blue -> Color -> Dotted -> Border -> Shape -> AnyRef -> Any
Finalmente, se agregará el
Circle
y el orden de linealización final será:Círculo -> Azul -> Color -> Punteado -> Borde -> Forma -> AnyRef -> Cualquiera
Este orden de linealización decide el orden de invocación de los métodos cuando se utiliza super
en cualquier clase o rasgo. La primera implementación del método desde la derecha se invoca, en el orden de linealización. Si se new MyShape().paint("Circle ")
, se imprimirá:
Circle with Blue Color with Dotted Border
Más información sobre la linealización se puede encontrar aquí .