我可以用虚拟课做什么?

oxb*_*kes 20 scala

我已经看到(并听到)关于向Scala 添加虚拟类的相当多的噪音(根据Martin Odersky的说法,它已经有虚拟类型).

什么是虚拟类型是什么,外行人的观点(可能是一个例子)是什么?Scala有什么可能的虚拟类?

([我没有使用过C或C++的经验,所以我希望任何答案都不要参考这些语言].)

Ale*_*nov 18

虚拟类型很简单:

  • 类和特征可以具有类型成员.例如

    trait Foo {
      type T
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 它们可以被细化(但一旦定义就不会被覆盖):

    class Foo1 extends Foo {
      type T <: AnyVal
    }
    
    class Foo2 extends Foo1 {
      override type T = Boolean
    }
    
    class Foo3 extends Foo2 {
      // override type T = Int // rejected by the compiler – would be unsound
    }
    
    Run Code Online (Sandbox Code Playgroud)

以下是Java-descendent语言中虚拟类的示例(cclass是一个虚拟类):

虚拟课程的特点

让我们看另一个例子来研究虚拟类的可能性.我们将使用虚拟课程以全新的功能扩展协作.假设我们有一个核心数据模型来表示表达式:

public cclass ExprModel {
   abstract public cclass Expr {}

   public cclass Constant extends Expr {
      protected int _val;
      public Constant(int val) { 
         _val = val;
      }                 
   }

   abstract public cclass BinaryExpr {
      protected Expr _left;
      protected Expr _right;
      public BinaryExpr(Expr left, Expr right) {
         _left = left;
         _right = right;
      }
   }

   public cclass Add extends BinaryExpr {}
   public cclass Mult extends BinaryExpr {} 
}
Run Code Online (Sandbox Code Playgroud)

协作将Expr定义为所有表达式的基类,表示常量的具体类,加法和乘法.BinaryExpr类使用两个操作数实现所有表达式的通用功能.请注意,当前版本的Caesar不支持在cclass中使用参数和抽象方法的构造函数.下面的代码演示了如何使用这种协作构建示例表达式:

public model.Expr buildSampleExpr(final ExprModel model) {
   model.Expr const1 = model.new Constant(-3);
   model.Expr const2 = model.new Constant(2);
   model.Expr op1 = model.new Mult(const1, const2);
   model.Expr const3 = model.new Constant(5);
   model.Expr op2 = model.new Add(op1, const3);
   return op2;
}
Run Code Online (Sandbox Code Playgroud)

协作将Expr定义为所有表达式的基类,表示常量的具体类,加法和乘法.BinaryExpr类使用两个操作数实现所有表达式的通用功能.

有许多与表达式相关的不同功能:它们的评估,将表达式格式化为简单文本的中缀或后缀顺序,各种一致性检查,查找和转换.我们希望将所有这些特定功能彼此分离并与核心数据模型分开.这可以通过虚拟类来实现.例如,下面的协作使用简单的表达式格式化功能扩展了核心模型:

public cclass ExprFormat extends ExprModel {
   abstract public cclass Expr {       
      abstract public void String format();
   }

   public cclass Constant {
      public void String format() { 
         return _val < 0 ? “(“ + _val + “)” : “” + _val; 
      }
   }

   abstract public cclass BinaryExpr {
      public void String format() { 
         return “(” + _left.format() + getOperSymbol() 
                    + _right.format() + “)”; 
      }
      abstract public void String getOperSymbol();
   }

   public cclass Add {
      public void String getOperSymbol() { return “+”; }
   }

   public cclass Mult {
      public void String getOperSymbol() { return “*”; }
   }
}
Run Code Online (Sandbox Code Playgroud)

这个简短的例子演示了虚拟类的各种功能:

  • 如果已经在超级合成中定义了虚拟类,则无需重复虚拟类之间的继承关系.例如,ExprModel将Constant定义为Expr的子类.这意味着Constant也被隐式假设为ExprFormat中Expr的子类.

  • 虚拟类可以使用旧版本中定义的字段和方法.例如,ExprFormat.BinaryExpr可以使用ExprModel.BinaryExpr中定义的_left和_right字段.

  • 可以在不使用类型转换的情况下访问已重写的虚拟类中定义的功能.例如,字段_Left和BinaryExpr的_right最初用)ExprModel的类型Expr的,其不具有方法格式(声明,但在ExprFormat的上下文expr的新版本被假定为_Left和_right的类型.因此可以在没有任何类型转换的情况下调用format().

  • 在覆盖的虚拟课堂中引入的方法可以再次重写在子类中的新版本.例如重写Expr的介绍方法格式(),其可以在BinaryExpr被覆盖.虽然添加和MULT不会进一步重写此方法,它们继承BinaryExpr的格式().

除了演示的属性外,重写的虚拟类也可以

  • 介绍新的数据字段,
  • 实现新的接口,
  • 引入新的继承关系.