Scala多态方法和显式引用
scala中的方法可以使用值和类型进行参数化。
值参数放在一对括号内,而类型参数放在一对括号内。
例如;
polymorphic.scala
object polymorphic { def main(args: Array[String]) { def add(a: Int, b: Int) { val c = a + b; println(c) } def addStrings(a: String, b: String) { val s = a + b println(s) } add(72, 67); addStrings("Hello", "World"); } }
在此示例中,+加号运算符用于添加数字以及连接字符串。
加法执行两个数字的加法并返回结果。
addString方法使用相同的+运算符,并连接用户指定的两个字符串。
这是Scala提供的默认运算符多态性。
下图显示了以上程序产生的输出。
Scala方法多态
现在,让我们看一个方法中多态的例子。
我们将编写一个通用方法来获取列表,并其中传递列表中的类型,默认值和项目数。
PolymorphicMethod.scala
object PolymorphicMethod { def getList[T](x:T, y:Int): List[T] = { if (y == 0) Nil else x :: getList(x, y - 1) } def main(args: Array[String]) { println(getList[Int](3,2)) println(getList[String]("Hi", 3)) } }
下图显示了在Scala IDE中执行上述程序时产生的输出。
Scala明确键入引用
有时我们需要在程序中明确指定值" this"的类型。
让我们看一下这种情况的示例。
我们有一个Train抽象类,如下所示。
Train.scala
abstract class Train { type Link; type Compartment <: CompartmentIntf abstract class CompartmentIntf { def join(compartment: Compartment): Link } def compartments: List[Compartment] def links: List[Link] def addCompartment: Compartment }
抽象类Train由链节和车厢列表组成。
定义了抽象类CompartmentIntf,并包含将Compartment作为参数的join方法。
声明了方法spacer,links和addCompartment,但是将在具体的类中定义实现。
现在,我们将定义抽象类MetroTrain,将火车类扩展为;
MetroTrain.scala
abstract class MetroTrain extends Train { type Link <: LinkImpl class LinkImpl(comptA: Compartment, comptB: Compartment) { def c1 = comptA def c2 = comptB } class CompartmentImpl extends CompartmentIntf { def join(compartment: Compartment): Link = { val link = newLink(this, compartment) links = link :: links link } } protected def newCompartment: Compartment protected def newLink(c1: Compartment, c2: Compartment): Link var compartments: List[Compartment] = Nil var links: List[Link] = Nil def addCompartment: Compartment = { val compartment = newCompartment compartments = compartment :: compartments compartment } }
此类提供了扩展Train类的部分实现。
实现细节是开放的,因此链接和隔离专区被抽象化了。
由于创建新的隔离专区和链接对象是必需的,因此我们添加了工厂方法newLink和newCompartment。
方法addCompartment和join是使用工厂方法定义的。
但是,上面的类将在第11行中引发编译错误为"类型不匹配;找到:CompartmentImpl.this.type(具有基本类型MetroTrain1.this.CompartmentImpl):MetroTrain1.this.Compartment",因为" this"被分配了CompartmentImpl类型,因此它与相应工厂方法要求的Compartment类型不兼容。
让我们通过如下对CompartmentImpl使用显式类型的自引用来解决这种类型不匹配的问题。
class CompartmentImpl extends CompartmentIntf { self: Compartment => def join(compartment: Compartment): Link = { val link = newLink(this, compartment) links = link :: links link } }
根据" CompartmentImpl"的新定义,其类型为Compartment。
我们指定显式类型的引用,以便" CompartmentImpl"表示要实例化的Compartment的子类型。
现在,我们将一个具体的类ConcreteMetroTrain定义为;
ConcreteMetroTrain.scala
class ConcreteMetroTrain extends MetroTrain { type Link = LinkImpl type Compartment = CompartmentImpl protected def newCompartment: Compartment = new CompartmentImpl protected def newLink(c1: Compartment, c2: Compartment): Link = new LinkImpl(c1, c2) }
现在我们可以实例化CompartmentImpl,因为现在我们知道CompartmentImpl表示Compartment类型的子类型。
现在创建一个Scala对象TestTrain作为;
TestTrain.scala
object TestTrain { def main(args: Array[String]) { println("Linking Compartments.....") val t: Train = new ConcreteMetroTrain val c1 = t.addCompartment val c2 = t.addCompartment val c3 = t.addCompartment c1.join(c2) c2.join(c3) } }