Scala Language
egenskaper
Sök…
Syntax
- drag ATrait {...}
- klass AClass (...) utökar ATrait {...}
- klass AClass förlänger BClass med ATrait
- klass AClass utökar ATrait med BTrait
- klass AClass utökar ATrait med BTrait med CTrait
- klass ATrait utökar BTrait
Stapelbar modifiering med drag
Du kan använda egenskaper för att ändra metoder i en klass, genom att använda egenskaper på stapelbart sätt.
Följande exempel visar hur drag kan staplas. Det är viktigt att beställa egenskaperna. Genom att använda olika ordningsföljder uppnås olika beteenden.
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
}
}
Observera att super
används för att åberopa roll()
-metoden i båda egenskaperna. Endast på detta sätt kan vi uppnå staplingsmodifiering. I fall av stapelbar modifiering bestäms metodinokallationsordning genom linjäriseringsregel .
Grundläggande egenskaper
Detta är den mest grundläggande versionen av ett drag i 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"
}
Eftersom ingen superklass är deklarerad för egenskap som kan Identifiable
, sträcker den sig som standard från AnyRef
klassen. Eftersom ingen definition för getIdentifier
finns i Identifiable
, den Puppy
måste klassen genomföra den. Dog Puppy
ärver implementeringen av printIdentification
från Identifiable
.
I REPL:
val p = new Puppy("K9", "Rex")
p.getIdentifier // res0: String = Rex has id K9
p.printIndentification() // Rex has id K9
Lösa diamantproblemet
Diamantproblemet , eller flera arv, hanteras av Scala med hjälp av egenskaper, som liknar Java-gränssnitt. Egenskaper är mer flexibla än gränssnitt och kan inkludera implementerade metoder. Detta gör drag som liknar mixins på andra språk.
Scala stöder inte arv från flera klasser, men en användare kan utöka flera drag i en enda klass:
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
Här grandChild
från både traitB
och traitC
, som i sin tur båda ärver från traitA
. Utgången (nedan) visar också prioritetsordningen när man löser vilka metodimplementeringar som kallas först:
C is a child of A.
B is a child of A.
This is the 'grandparent' trait.
Observera att när super
används för att åberopa metoder i class
eller trait
kommer linjäriseringsregel att spela för att bestämma samtalshierarki. Lineariseringsorder för grandChild
kommer att vara:
grandChild -> traitC -> traitB -> traitA -> AnyRef -> Any
Nedan är ett annat exempel:
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!")
}
}
Detta program skriver ut:
*************
-------------
Hello World!
Linjärisering för CustomPrinter
kommer att vara:
CustomPrinter -> DelimitWithStar -> DelimitWithHyphen -> Skrivare -> AnyRef -> Vilket som helst
linjärisering
Vid staplingsmodifiering arrangerar Scala klasser och drag i en linjär ordning för att bestämma metodsamtalshierarki, som kallas linearisering . Lineariseringsregeln används endast för de metoder som involverar metodinokallering via super()
. Låt oss överväga detta genom ett exempel:
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)
}
}
Linearisering sker bakifrån och fram . I detta fall,
First
Shape
kommer att lineariseras, vilket ser ut som:Shape -> AnyRef -> Any
Då
Dotted
linjäriseras:Dotted -> Border -> Shape -> AnyRef -> Any
Nästa i rad är
Blue
. Normalt kommerBlue
: s linearisering att vara:Blue -> Color -> Shape -> AnyRef -> Any
för i
MyShape
linearisering fram till nu ( steg 2 ) harShape -> AnyRef -> Any
redan dykt upp. Därför ignoreras det. Således kommer denBlue
lineariseringen att vara:Blue -> Color -> Dotted -> Border -> Shape -> AnyRef -> Any
Slutligen läggs
Circle
till och den slutliga linjäriseringsordningen är:Cirkel -> Blå -> Färg -> Prickad -> Kant -> Form -> AnyRef -> Vilket som helst
Denna linjäriseringsordning bestämmer invokningsordning för metoder när super
används i någon klass eller drag. Den första metodimplementeringen från höger åberopas i lineariseringsordningen. Om new MyShape().paint("Circle ")
körs kommer den att skriva ut:
Circle with Blue Color with Dotted Border
Mer information om linearisering kan hittas här .