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,

  1. First Shape kommer att lineariseras, vilket ser ut som:

    Shape -> AnyRef -> Any

  2. Dotted linjäriseras:

    Dotted -> Border -> Shape -> AnyRef -> Any

  3. Nästa i rad är Blue . Normalt kommer Blue : s linearisering att vara:

    Blue -> Color -> Shape -> AnyRef -> Any

    för i MyShape linearisering fram till nu ( steg 2 ) har Shape -> AnyRef -> Any redan dykt upp. Därför ignoreras det. Således kommer den Blue lineariseringen att vara:

    Blue -> Color -> Dotted -> Border -> Shape -> AnyRef -> Any

  4. 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 .



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow