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

