我是Scala的新手,不知道为什么我必须在下面的代码中对路径依赖类型做一个(不直观的)类型转换。 (我不喜欢getter,setter或nulls,他们在这里分开操作并消除错误的来源)
// Module A public API
class ModA {
trait A
}
// Module B public API that depends on types defined in Module A
class ModB(val modA: ModA) {
trait B {
def getA: modA.A;
def setA(anA: modA.A);
}
}
// One implementation of Module A
class ModAImpl extends ModA {
class AImpl extends A
}
// One implementation of Module B
class ModBImpl(mod: ModA) extends ModB(mod) {
class BImpl extends B {
private[this] var privA: modA.A = _;
override def getA = privA;
override def setA(anA: modA.A) = privA = anA;
}
}
object Main {
def main(args: Array[String]): Unit = {
// wiring the modules
val modAImpl = new ModAImpl;
val modBImpl = new ModBImpl(modAImpl);
// wiring objects
val a = new modAImpl.AImpl;
val b = new modBImpl.BImpl;
b.setA(a); //don't compile and complain: type mismatch; found: modAImpl.A required: modBImpl.modA.A
//i have to do this horrible and coutnerintuitive cast to workaround it
b.setA(a.asInstanceOf[modBImpl.modA.A]);
var someA: modAImpl.A = null;
someA = b.getA; // don't compile with same reason
someA = b.getA.asInstanceOf[modAImpl.A]; // horrible cast to workaround
println(a == b.getA); // however this prints true
println(a eq b.getA); // this prints true too
}
}
我已经阅读过有关单例类型的信息,以便在两种类型相同时通知编译器,但我不知道如何在此处应用它。 提前谢谢。
答案 0 :(得分:5)
您可以在ModB
类型上添加类型参数:
class ModA { trait A }
class ModB[AA](val modA: ModA { type A = AA }) {
trait B {
def getA: AA
def setA(anA: AA)
}
}
class ModAImpl extends ModA { class AImpl extends A }
class ModBImpl[AA](
mod: ModA { type A = AA }) extends ModB(mod) {
class BImpl extends B {
private[this] var privA: AA = _
override def getA = privA
override def setA(anA: AA) = privA = anA
}
}
类型推断全部按照需要进行:
scala> val modAImpl = new ModAImpl
modAImpl: ModAImpl = ModAImpl@7139edf6
scala> val modBImpl = new ModBImpl(modAImpl)
modBImpl: ModBImpl[modAImpl.A] = ModBImpl@1dd7b098
scala> val a = new modAImpl.AImpl
a: modAImpl.AImpl = ModAImpl$AImpl@4cbde97a
scala> val b = new modBImpl.BImpl
b: modBImpl.BImpl = ModBImpl$BImpl@63dfafd6
scala> b.setA(a)
答案 1 :(得分:0)
让我们从简化代码开始,消除不必要的复杂性。
class Aout {
class Ain
}
class Bout(val link: Aout) {
class Bin(val field: link.Ain)
}
object Main {
def main(args: Array[String]): Unit = {
// wiring outer object
val aout: Aout = new Aout;
val bout: Bout = new Bout(aout);
// wiring inner object
val ain: aout.Ain = new aout.Ain;
val bin: bout.Bin = new bout.Bin(ain); //don't compile and complain: type mismatch; found: aout.Ain required: bout.link.Ain
}
}
答案:
编译器抱怨类型不匹配错误,因为他比较了赋值中涉及的两个声明类型的路径,并且它们是不同的。
编译器不够智能,无法注意到此时aout eq bout.link
。你必须告诉他。
因此,替换行
val ain: aout.Ain = new aout.Ain;
使用
val ain: bout.link.Ain = new bout.link.Ain;
解决与路径有关的类型不匹配。
无论如何,仅在原始代码中更正类型的路径是不够的,因为还存在继承问题。
一种解决方法是像这样使类ModBImpl
知道ModAImpl
类:
class ModA {
trait A
}
class ModB[M <: ModA](val modA: M) { // type parameter added
trait B {
def getA: modA.A;
def setA(anA: modA.A);
}
}
class ModAImpl extends ModA {
class AImpl extends A
}
class ModBImpl(mod: ModAImpl) extends ModB(mod) { // changed type of `mod` parameter from `ModA` to `ModAImpl`
class BImpl extends B {
private[this] var privA: modA.A = _;
override def getA: modA.A = privA;
override def setA(anA: modA.A): Unit = privA = anA;
}
}
object Main {
def main(args: Array[String]): Unit = {
val modAImpl = new ModAImpl;
val modBImpl = new ModBImpl(modAImpl);
val a: modBImpl.modA.AImpl = new modBImpl.modA.AImpl; // changed the path of the type
val b: modBImpl.BImpl = new modBImpl.BImpl;
b.setA(a); // here IntellijIde complains with a type mismatch error, but the ScalaIDE (eclipse) and the scala compiler work fine.
}
}
如果您的业务规则不允许ModBImpl
类拥有ModAImpl
类的知识,请告诉我,以便我们找到另一种解决方案。