수색…


통사론

  • 형질 ATrait {...}
  • 클래스 AClass (...)는 ATrait {...}를 확장합니다.
  • class AClass는 ATclass와 함께 BClass를 확장합니다.
  • AClass 클래스는 ATrait와 BTrait를 확장합니다.
  • class AClass는 CTrait와 함께 BTrait와 함께 ATrait를 확장합니다.
  • ATrait는 BTrait를 확장시킨다.

특성을 이용한 스택 가능 수정

형질을 사용하여 형질을 사용하여 클래스의 메소드를 수정할 수 있습니다.

다음 예는 형질을 어떻게 쌓을 수 있는지 보여줍니다. 형질의 순서가 중요합니다. 다른 특성의 순서를 사용하여 다른 행동이 성취됩니다.

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
  }
}

super 는 두 특성 모두에서 roll() 메소드를 호출하는 데 사용됩니다. 이 방법으로 만 스택 적 수정을 수행 할 수 있습니다. 스택 가능 수정의 경우, 메소드 호출 순서는 선형화 규칙에 의해 결정됩니다.

특성 기본 사항

이것은 스칼라에서 가장 기본적인 특성의 버전입니다.

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"
}

Identifiable 할 수있는 특성에 대해 수퍼 클래스가 선언되지 않으므로 기본적으로 AnyRef 클래스에서 확장됩니다. Identifiable 에는 getIdentifier 에 대한 정의가 없기 때문에 Puppy 클래스는이를 구현해야합니다. 그러나 PuppyIdentifiable 에서 printIdentification 구현을 상속받습니다.

REPL에서 :

val p = new Puppy("K9", "Rex")
p.getIdentifier  // res0: String = Rex has id K9
p.printIndentification()  // Rex has id K9

다이아몬드 문제 해결

다이아몬드 문제 또는 다중 상속은 Java 인터페이스와 유사한 Traits을 사용하여 Scala에서 처리합니다. 특성은 인터페이스보다 유연하며 구현 된 방법을 포함 할 수 있습니다. 이것은 다른 언어의 mixin 과 비슷한 특성을 만듭니다.

스칼라는 여러 클래스의 상속을 지원하지 않지만 사용자는 단일 클래스에서 여러 특성을 확장 할 수 있습니다.

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

여기 grandChildtraitBtraitC 모두에서 상속을 traitA . traitAtraitA 상속받습니다. 출력 (아래)은 어떤 메소드 구현이 먼저 호출되는지를 결정할 때 우선 순위를 보여줍니다 :

C is a child of A. 
B is a child of A. 
This is the 'grandparent' trait.

superclass 또는 trait 메서드를 호출하는 데 사용되는 경우 호출 계층 구조를 결정하기 위해 선형화 규칙이 적용됩니다. grandChild 선형화 순서는 다음과 같습니다.

grandChild -> traitC -> traitB -> traitA -> AnyRef -> Any


다음은 또 다른 예입니다.

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!")
  }
}

이 프로그램은 다음을 인쇄합니다.

*************
-------------
Hello World!

CustomPrinter 선형화는 다음과 같습니다.

CustomPrinter -> DelimitWithStar -> DelimitWithHyphen -> Printer -> AnyRef -> Any

선형화

스택 가능 수정의 경우 스칼라는 클래스 및 특성을 선형 순서로 정렬하여 메서드 호출 계층을 결정합니다.이를 선형화라고 합니다. 선형화 규칙은 super() 를 통한 메소드 호출과 관련된 메소드 에만 사용 됩니다 . 이를 예로 들어 보겠습니다.

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)
  }
}

선형화는 뒤에서 앞으로 일어난다. 이 경우,

  1. First Shape 는 다음과 같이 선형화됩니다.

    Shape -> AnyRef -> Any

  2. 그런 다음 Dotted 가 선형화됩니다.

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

  3. 다음 줄은 Blue 입니다. 일반적으로 Blue 의 선형화는 다음과 같습니다.

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

    왜냐하면 MyShape 의 선형화 ( Step 2 )까지는 Shape -> AnyRef -> Any 가 이미 나타 Shape -> AnyRef -> Any 때문입니다. 따라서 무시됩니다. 따라서 Blue 선형화는 다음과 같습니다.

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

  4. 마지막으로 Circle 이 추가되고 최종 선형화 순서가 다음과 같이됩니다.

    원 -> 파랑 -> 색상 -> 점선 -> 테두리 -> 모양 -> AnyRef -> Any

이 선형화 순서는 super 클래스가 어떤 클래스 나 특성에서 사용될 때 메소드의 호출 순서를 결정합니다. 오른쪽에서부터 첫 번째 메소드 구현이 선형화 순서로 호출됩니다. new MyShape().paint("Circle ") 가 실행되면 다음과 같이 인쇄됩니다.

Circle with Blue Color with Dotted Border 

선형화에 대한 자세한 내용은 여기를 참조하십시오 .



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow