📜  Scala 中的特征线性化

📅  最后修改于: 2022-05-13 01:54:26.135000             🧑  作者: Mango

Scala 中的特征线性化


Scala 线性化是一个确定性过程,当创建一个类的对象时发挥作用,该类对象是使用不同特征和类的继承定义的。线性化有助于解决当一个类或特征从 2 个不同的具体类或特征继承相同属性时出现的菱形问题。

句法 :

trait C{}
trait B{}
class A{}
object a_obj= new class A extends B with C

线性化将如下所示:-

C-> AnyRef-> Any   
B-> AnyRef-> Any   
A-> AnyRef-> Any    
a_obj-> A-> C-> B-> AnyRef-> Any     

这里Any是所有类的超类,也称为顶级类。它定义了某些通用方法,例如 equals、hashCode 和 toString。 AnyRef代表参考类。所有非值类型都定义为引用类型。 AnyRef 对应于Java.lang.object 。每个 Scala 特征和类都在线性化层次结构的末尾隐式扩展这些 Scala 对象。

例子 :

// Scala program defining trait A
trait A
{
    def name: String
}
  
// defining trait B inheriting A
trait B extends A
{
    override def name: String ="class b"
}
  
// defining trait C inheriting A
trait C extends A
{
    override def name: String ="class c"
}
  
// defining class D inheriting B and C both
class D extends B with C
{
    override def name: String = super.name
}
  
// Creating object
object GFG
{
    // Main method
    def main(args: Array[String])
    {
        var class_d = new D
          
        // whose property will be inherited
        println(class_d.name)
    }
}

输出 :

class c

D 类的线性化遵循黑色粗体箭头。 D 类的继承遵循光箭头。

特征线性化和继承图

正如我们在上图中看到的那样,线性化与继承结构不同。 Scala 特征/类以线性顺序动态放置,线性化将如下应用。

D-> C-> B-> A-> AnyRef-> Any

确定线性化遵循以下规则:

  1. 取第一个扩展特征/类,并以垂直形式编写其完整的继承层次结构,将此层次结构存储为 X。
  2. with子句之后的下一个 trait/class,写下其完整的层次结构,并取消在层次结构 X 中重复的类或特征。将剩余的特征/类添加到层次结构 X 的前面。
  3. 转到第 2 步并重复该过程,直到没有特征/类被遗漏。
  4. 将类本身放在层次结构的前面,作为编写层次结构的头。

让我们理解一些例子。
例子 :

// Scala program for linearization
// defining old_car class
class old_Car
{
    def method: String= "old car "
}
  
// defining new_Car_Designs trait
trait new_Car_Designs extends old_Car
{
    override def method: String ="Designing-> "+ super.method
}
  
// defining new_Car_Part trait
trait new_Car_Part extends old_Car
{
    override def method: String = "Add new part-> "+ super.method
}
  
// defining new_Car_Paint trait
trait new_Car_Paint extends old_Car
{
    override def method: String = "Repainting-> "+ super.method
}
  
// defining new_Car class
class new_Car extends new_Car_Paint with 
new_Car_Part with new_Car_Designs
{
    override def method: String = "new car-> "+ super.method
}
  
// Creating object
object geekforgeeks
{
    // Main method
    def main(args: Array[String])
    {
        // new_Car object
        var car1 = new new_Car
        println(car1.method)
    }
}

输出 :

new car-> Designing-> Add new part-> Repainting-> old car 

例子 :

// Scala program for trait linearization
// defining classes and traits
class flavour 
{
    def make (flavour: String): Unit = 
    {
        println(flavour)
    }
}
  
// defining texture trait
trait texture extends flavour
{
    abstract override def make (flavour : String) 
    {
        super.make(flavour + "texture ")
    }
}
  
// defining cream trait
trait cream extends texture 
{
    abstract override def make (flavour : String)
    {
        super.make(flavour + "with cream ")
    }
}
  
// defining jelly trait
trait jelly extends texture 
{
    abstract override def make (flavour : String)
    {
        super.make(flavour + "with jelly ")
    }
}
// defining cone trait
trait cone extends flavour 
{
    abstract override def make (flavour : String)
    {
        super.make(flavour + "in cone ")
    }
}
  
// creating new ice-cream flovours 
// with above traits and classes
// inheriting different traits and classes
class Myflavour extends flavour with jelly 
{
    override def make (flavour : String) 
    {
        super.make(flavour)
    }
}
class Myflavour2 extends flavour with cream with cone
{
    override def make (flavour : String)
    {
        super.make(flavour)
    } 
}
  
// Creating object
object GFG
{
    // Main method
    def main(args: Array[String])
    {
        // creating new objects
        var icecream1 = new Myflavour
        var icecream2 = new Myflavour2 with jelly
        println(icecream1.make("chocolate "))
        println(icecream2.make("vanilla ")) 
    }
}

输出 :

chocolate with jelly texture 
()
vanilla with jelly in cone with cream texture 
()

关于线性化的要点

  • Scala 通过线性化过程解决了特征/类的歧义。
  • 每当实例化一个新类时,Scala 都会使用线性化。获取所有特征/类并形成指向相应超类/特征的线性顺序,因此方法知道其父方法。
  • 这些超级方法调用是以可堆叠的方式完成的。
  • 线性化可能与编写时继承的 mixin 相同,也可能不同。
  • 当一个类已经在线性化中被隐式继承时,我们不能显式地将其添加到继承中,否则将导致两次继承错误。
  • 线性化中不会重复任何特征/类。