เริ่มจากการพึ่งพาวงจร
trait A {
selfA: B =>
def fa: Int }
trait B {
selfB: A =>
def fb: String }
อย่างไรก็ตามโมดูลของโซลูชันนี้ไม่ดีเท่าที่อาจปรากฏขึ้นครั้งแรกเนื่องจากคุณสามารถแทนที่ชนิดของตัวเองดังนี้:
trait A1 extends A {
selfA1: B =>
override def fb = "B's String" }
trait B1 extends B {
selfB1: A =>
override def fa = "A's String" }
val myObj = new A1 with B1
แม้ว่าหากคุณแทนที่สมาชิกของประเภทตนเองคุณจะไม่สามารถเข้าถึงสมาชิกดั้งเดิมซึ่งยังสามารถเข้าถึงได้ผ่านการใช้การสืบทอดขั้นสูง ดังนั้นสิ่งที่ได้รับมากกว่าการใช้มรดกคือ:
trait AB {
def fa: String
def fb: String }
trait A1 extends AB
{ override def fa = "A's String" }
trait B1 extends AB
{ override def fb = "B's String" }
val myObj = new A1 with B1
ตอนนี้ฉันไม่สามารถเรียกร้องให้เข้าใจรายละเอียดปลีกย่อยทั้งหมดของลวดลายเค้กได้ แต่มันทำให้ฉันรู้สึกว่าวิธีการบังคับใช้โมดุลที่เป็นโมดูล่านั้นได้มาจากองค์ประกอบมากกว่าการสืบทอดหรือประเภทของตัวเอง
เวอร์ชันการสืบทอดสั้นกว่า แต่เหตุผลหลักที่ฉันชอบการสืบทอดมากกว่าประเภทตัวเองคือฉันพบว่ามันยากกว่ามากในการรับลำดับการเริ่มต้นที่ถูกต้องกับประเภทของตนเอง อย่างไรก็ตามมีบางสิ่งที่คุณสามารถทำกับประเภทของตัวเองที่คุณไม่สามารถทำกับมรดก ประเภทตนเองสามารถใช้ประเภทในขณะที่การสืบทอดต้องมีลักษณะหรือชั้นเรียนเช่น:
trait Outer
{ type T1 }
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.
คุณสามารถทำได้:
trait TypeBuster
{ this: Int with String => }
แม้ว่าคุณจะไม่สามารถยกตัวอย่างได้ ฉันไม่เห็นเหตุผลที่แน่นอนว่าไม่สามารถสืบทอดจากประเภทได้ แต่ฉันรู้สึกว่ามันจะมีประโยชน์หากมีคลาสตัวสร้างเส้นทางและคุณสมบัติตามที่เรามีลักษณะตัวสร้าง / คลาสของตัวสร้าง อย่างน่าเสียดาย
trait InnerA extends Outer#Inner //Doesn't compile
เรามีสิ่งนี้:
trait Outer
{ trait Inner }
trait OuterA extends Outer
{ trait InnerA extends Inner }
trait OuterB extends Outer
{ trait InnerB extends Inner }
trait OuterFinal extends OuterA with OuterB
{ val myV = new InnerA with InnerB }
หรือสิ่งนี้:
trait Outer
{ trait Inner }
trait InnerA
{this: Outer#Inner =>}
trait InnerB
{this: Outer#Inner =>}
trait OuterFinal extends Outer
{ val myVal = new InnerA with InnerB with Inner }
ประเด็นหนึ่งที่ควรเอาใจใส่มากกว่านี้ก็คือคุณลักษณะนั้นสามารถขยายชั้นเรียนได้ ขอบคุณ David Maclver ที่ชี้เรื่องนี้ออกมา นี่คือตัวอย่างจากรหัสของฉัน:
class ScnBase extends Frame
abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] )
{ val geomR = geomRI }
trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
ScnBase
สืบทอดมาจากคลาสSwing Frame ดังนั้นจึงสามารถใช้เป็นประเภทตัวเองแล้วผสมในตอนท้าย (ที่ instantiation) อย่างไรก็ตามval geomR
จำเป็นต้องเริ่มต้นใหม่ก่อนที่จะถูกใช้โดยการสืบทอดคุณสมบัติ ดังนั้นเราจึงจำเป็นชั้นเรียนในการบังคับใช้ initialisation geomR
ก่อน ชั้นScnVista
นั้นจะสามารถสืบทอดจากหลายลักษณะ orthogonal ซึ่งตัวเองสามารถสืบทอด การใช้พารามิเตอร์หลายประเภท (ข้อมูลทั่วไป) นำเสนอรูปแบบทางเลือกของโมดุล